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 或 HAVING 子句中,且必须有对应 GROUP BY。
- 正确写法示例(查每个角色组下全员都开启的权限位):
SELECT role_id, BIT_AND(COALESCE(perm_mask, 0)) AS common_bits FROM role_perms GROUP BY role_id
- 错误写法:
SELECT * FROM users WHERE BIT_AND(perm_mask) & 4 = 4—— 语法非法,语义也错 - 如果漏掉
GROUP BY,MySQL 会拒绝执行,PostgreSQL 直接报函数不存在
单用户权限检查别用 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) - 字段若为字符串类型(如
'12'),&仍可工作(MySQL 隐式转整数),但行为不可靠,应提前CAST(perm_mask AS UNSIGNED)
NULL 值会让 BIT_AND/BIT_OR 结果变 NULL,必须用 COALESCE 拦住
BIT_AND 要求该组**所有非 NULL 行**在某一位上都是 1 才返回 1;只要有一行是 NULL,整组结果就不可靠。MySQL 会跳过 NULL,但全为 NULL 时返回 NULL,导致 HAVING BIT_AND(perm_mask) & 4 = 4 永远不成立(NULL = 4 是 unknown)。
- 安全写法:
BIT_AND(COALESCE(perm_mask, 0)),把NULL统一转为 0,确保交集计算可控 - 同理,
BIT_OR(COALESCE(perm_mask, 0))防止全NULL组返回NULL而非 0 - 别依赖数据库默认行为:KingbaseES、MySQL 行为一致,但 PostgreSQL 的
bit_or()要求先转bit(n)类型,否则报错
不同数据库对 BIT_AND/BIT_OR 支持差异极大
MySQL 8.0.17+ 原生支持;老版本、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()(需先perm_mask::bit(64)) - SQL Server:无内置等价物,
POWER(2,n)+SUM只能处理固定位;最现实的是查出所有值,在应用层用reduce(lambda a,b: a|b, values)合并 - 字段类型必须是整型:字符串如
'101'会被静默转成十进制 101,而非二进制 5 —— 这不是 bug,是隐式转换规则
真正容易被忽略的是:BIT_AND/BIT_OR 无法走索引,大数据量分组性能差;而单行 & 查询可以配合 INDEX(perm_mask) 优化。别为了“看起来高级”强行套用聚合函数,多数权限校验场景它根本不该出场。










