BIT_AND和BIT_OR仅用于分组聚合多行权限交集或并集,不可用于单用户权限判断;单行校验必须用&运算符,如WHERE (perm_mask & 4) = 4,且二者必须配合GROUP BY使用,否则报错。

BIT_AND 和 BIT_OR 不是用来查“某个用户有没有权限”的,它们只在统计多行数据的共性或并集时才有效;单行权限判断必须用 & 或 | 运算符。
BIT_AND 和 BIT_OR 必须配合 GROUP BY 使用
这两个函数不是过滤工具,而是跨行逐位聚合操作符。写成 WHERE BIT_AND(perm_mask) = 4 会直接报错:Invalid use of group function。
- 正确用法是:先分组,再聚合,例如统计每个角色组下“全员都开启的权限位”:
SELECT role_id, BIT_AND(perm_mask) AS common_bits FROM role_perms GROUP BY role_id -
BIT_AND返回某一位为 1,当且仅当该组**所有非 NULL 行**在该位上都是 1;BIT_OR返回某一位为 1,只要该组**至少一行**在该位上是 1 - NULL 值会让整组结果变
NULL,必须提前用COALESCE(perm_mask, 0)拦住,否则交集结果不可靠
单用户权限检查别用 BIT_AND/BIT_OR,用 & 运算符
生产环境里 95% 的权限校验根本不会出现 BIT_AND,而是直接在 WHERE 中用 & 判断掩码位是否置位。
- 查“用户是否有删除权限(bit 2,值为 4)”:
WHERE (perm_mask & 4) = 4——括号不能省,因为&优先级低于= - 查“同时有读(bit 0 = 1)和写(bit 1 = 2)权限”:
WHERE (perm_mask & 3) = 3(因为 1 | 2 = 3) - 查“有读或删除权限(至少一个)”:
WHERE (perm_mask & 5) != 0(5 = 101b,覆盖 bit 0 和 bit 2)
不同数据库对位聚合的支持差异很大
MySQL 8.0.17+ 才原生支持 BIT_OR/BIT_AND;老版本、PostgreSQL、SQL Server 都得绕路,且方式完全不同。
- MySQL 5.7 及更早:只能用用户变量模拟,且必须在同一语句中初始化、累加、输出,还要显式
ORDER BY:SELECT @acc FROM (SELECT @acc := 0) init, (SELECT @acc := @acc | perm_mask FROM t ORDER BY id) calc - PostgreSQL:没有
BIT_OR函数,但有int8or()(推荐)或bit_or()(需先转bit(n)类型,长度不够会截断) - SQL Server:无内置位聚合函数,
POWER(2,n)+SUM只能处理固定位;最现实的是查出所有整数值,在应用层用reduce(lambda a,b: a|b, values)合并
字符串字段存权限掩码时必须先转整型
如果 perm_mask 是字符串类型(比如 '12' 或 '1010'),直接丢给 BIT_OR 会静默转成十进制整数 12 或 1010,而不是按二进制解析——这不是 bug,是 MySQL 隐式转换规则。
- 想把二进制字符串
'1010'当作位掩码处理,得先用CONV('1010', 2, 10)转成整数 10 - 如果是十进制字符串
'12',用CAST(perm_str AS UNSIGNED)更安全 - 没转就聚合,结果全是错的,而且很难排查——因为不报错,只是逻辑失效
真正容易被忽略的是:位聚合函数无法走索引,数据量一过十万行,GROUP BY + BIT_AND 就明显变慢;而单行 & 查询虽然也用不上索引,但胜在快且确定。别为了“看起来统一”硬把单行判断塞进聚合逻辑里。


















