type
status
date
slug
summary
tags
category
icon
password
题目
下面的t1表中的数据为用户A的访问记录,请计算每个月的访问的天数。返回 year,month,days 格式。
正确结果返回应该为:
答案一
答案二
分析
我的答案
一开始,我想着,先对年月日进行一次去重,因为只需要计算一个月的天数,所以重复的数据是没有用的。
然后,在上面的结果的基础上,根据年月进行分组计算日的数量。
标准答案
然而,看了一眼标准答案,惊为天人,用了两个位运算的函数
BIT_COUNT
与 BIT_OR
,还有左移符号 <<
。看第一眼,没看懂了,看第二眼,还是没有看懂。
BIT_COUNT
计算对应的数的二进制中的1的数量,例如
BIT_OR
可以理解为按位或,就是对 select出来的字段的值的列表,进行所有按位或操作。
继续分析:
1<<day
:这是一个位左移操作。它将数字1向左移动day
位。在这里,day
很可能是一个代表月份中某一天的字段。例如,如果day
是2,那么1<<day
的结果是4(二进制中的100
),这相当于2的day
次方。
BIT_OR(1<<day)
:BIT_OR
是一个聚合函数,它对组内所有行执行位或(bitwise OR)操作。在这个查询中,它将同一个year
和month
组内的所有1<<day
的结果进行位或操作。这样,每个不同的day
都会在结果中设置一个位。因为每个月的天数是唯一的,所以这个操作最终会产生一个整数,其二进制表示中的位数表示该月中出现的不同天数。【不超过32天,位数不会超过31,可以使用BIT_OR
】
BIT_COUNT(BIT_OR(1<<day))
:BIT_COUNT
函数计算一个数字的二进制表示中1的数量。在这个查询中,它计算上一步BIT_OR
操作结果中的位数,这个位数就是该月中有记录的不同天数。
GROUP BY year,month
:这个语句指示MySQL按照年和月来分组记录。对于每个组,上述的位运算将单独执行。
综上所述,这个查询对于每个月份,计算了
t1
表中有记录的不同天数。这种方法特别适用于处理稀疏数据,即不是每一天都有记录的情况。通过位运算,它能高效地对存在记录的天数进行计数,而不需要存储一个完整的日期列表。总结
位运算的函数还是挺有效的,学习了。
- 作者:eachenkuang
- 链接:https://kuangyichen.com/article/a-sql-problem-thinking
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。