如何通过单SQL查询统计64位状态字段中各任务的完成用户数?
优雅解决64位状态位的单查询统计方案
嘿,我完全懂你这种要查64次的痛苦!其实不用逐个任务去查,我们可以借助数字序列生成+字符串/位运算的方式,用一次查询搞定所有任务的完成数统计。下面分两种常见的存储场景给你具体方案:
场景1:status是字符串类型(比如CHAR(64))
如果你的status是按十进制字符串存储的(比如示例里的1100、1001这种),我们可以先生成1到64的任务编号序列,然后批量提取每个任务对应的位并求和:
MySQL示例代码
WITH RECURSIVE task_ids AS ( SELECT 1 AS task_id UNION ALL SELECT task_id + 1 FROM task_ids WHERE task_id < 64 ) SELECT ti.task_id, SUM(CAST(SUBSTRING(your_table.status, ti.task_id, 1) AS UNSIGNED)) AS completed_user_count FROM task_ids ti CROSS JOIN your_table GROUP BY ti.task_id ORDER BY ti.task_id;
小提示:
- 如果你的任务编号是从右往左对应字符串的位(比如字符串最后一位是任务1),把
SUBSTRING的位置参数改成LENGTH(your_table.status) - ti.task_id + 1就行。 - 要是你的数据库不支持递归CTE(比如MySQL 5.x),提前建个包含1到64的数字表(比如叫
numbers)替换掉CTE部分就行。
场景2:status是整数类型(用二进制位存状态)
如果status实际是用64位整数的二进制位来记录状态(比如十进制10对应二进制1010,代表任务2、4完成),那用位运算效率会更高:
MySQL示例代码
WITH RECURSIVE task_ids AS ( SELECT 1 AS task_id UNION ALL SELECT task_id + 1 FROM task_ids WHERE task_id < 64 ) SELECT ti.task_id, SUM( (your_table.status >> (ti.task_id - 1)) & 1 ) AS completed_user_count FROM task_ids ti CROSS JOIN your_table GROUP BY ti.task_id ORDER BY ti.task_id;
原理说明:
>> (ti.task_id - 1):把目标任务对应的二进制位右移到最低位(比如任务1对应第0位,所以移0位;任务2对应第1位,移1位)。& 1:提取最低位的数值(0或1),然后用SUM直接统计完成的用户数。
额外优化建议
如果你的数据量特别大,CROSS JOIN可能会生成较多临时数据,不过64次的笛卡尔积其实还好,百万级数据也能轻松处理。要是担心性能,也可以把数字序列表做成物理表,提前插入1到64的记录,查询时直接关联就行。
内容的提问来源于stack exchange,提问作者user2894829
相关产品推荐
相关产品推荐

