BIT_OR和BIT_AND是按位聚合函数,非数值求和:BIT_OR(1,2,4)得7(0111),BIT_OR(3,3)仍为3;BIT_AND求所有行对应位全为1的交集,二者均需防NULL且仅适用于权限、状态等位图场景。

BIT_OR 和 BIT_AND 是什么,为什么不能直接当 SUM 用?
它们是位运算聚合函数,不是数值累加。比如 BIT_OR(1, 2, 4) 得到 7(二进制 0111),因为把各数对应位“或”起来;而 SUM(1, 2, 4) 是 7 只是巧合,BIT_OR(3, 3) 还是 3(二进制 011 | 011 = 011),但 SUM(3, 3) 是 6。误当求和用会悄悄出错。
什么时候该用 BIT_OR 而不是 GROUP_CONCAT?
当你在做权限、状态、开关类标记的合并时——比如用户有多个角色,每个角色用一个 bit 表示(管理员=1,编辑=2,审核员=4),想快速知道某组用户 collectively 拥有哪些权限,BIT_OR(role_flag) 一行就搞定;用 GROUP_CONCAT 得到字符串 "1,2,4",后续还得解析、去重、转数字,没法直接参与位判断。
- 适用场景:权限掩码、功能开关组合、状态位图(如文件属性:只读=1、隐藏=2、系统=4)
- 不适用场景:需要保留原始值个数、顺序、重复信息时
- 注意 MySQL 5.7+ 才支持窗口函数形式的
BIT_OR(),8.0+ 更稳定;MariaDB 10.3+ 支持,但旧版可能只有BIT_OR()作为聚合函数,不支持表达式参数
常见错误:NULL 值让整个 BIT_OR 结果变 NULL
只要分组里有一个 role_flag 是 NULL,BIT_OR(role_flag) 就返回 NULL,哪怕其他全是非空整数。这不是 bug,是 SQL 标准行为(聚合函数对 NULL 敏感)。修复方法很简单:
- 用
COALESCE(role_flag, 0)把 NULL 转成 0(不影响位或结果) - 或者加
WHERE role_flag IS NOT NULL过滤掉无效行 - 别用
IFNULL(role_flag, 0)—— 它在某些老版本 MySQL 中可能触发隐式类型转换,导致位运算异常
示例:
SELECT user_group, BIT_OR(COALESCE(role_flag, 0)) AS combined_flags FROM user_roles GROUP BY user_group;
BIT_AND 的陷阱:它求的是“所有成员共同拥有的位”,不是“并集”
BIT_AND 容易被名字误导。比如三个人的权限分别是 7(0111)、3(0011)、5(0101),BIT_AND 结果是 1(0001)——只有第 0 位在三个数中都为 1。这适合找交集场景(如“这个组里所有人都具备的功能”),但绝不是“汇总所有功能”。
- 典型用途:检查一组记录是否全部开启某个开关(比如
BIT_AND(status & 8) > 0判断是否全为“已归档”) - 性能注意:
BIT_AND和BIT_OR都是 O(n) 扫描,无索引加速;大数据量下别在没 WHERE 的大表上直接跑 - 兼容性提醒:PostgreSQL 没原生
BIT_AND/BIT_OR聚合,得用bool_and(bool_or())组合模拟,或自定义聚合函数
真正难的不是写法,是确认业务语义到底要“并集”还是“交集”,以及是否允许 NULL 干扰结果——这两个点漏掉,查出来的数据看着像对,其实已经错了。

















