MySQL中&是位运算符,对整型字段执行按位与操作,非零结果视为真从而过滤出对应行;它要求操作数为整型,不支持字符串或NULL直接参与,语义为二进制逐位计算。

MySQL里&直接写在WHERE里为什么能过滤?
因为 MySQL 把非零整数当作真值处理,status & 4结果只要不为 0(即第 3 位是 1),整个表达式就为真,行就被保留。不需要显式写 = 4 或 > 0——但强烈建议写清楚,否则可读性差、易出错。
常见错误现象:
-
SELECT * FROM users WHERE status & 4;能跑通,但别人看不懂你在筛什么 - 如果
status是VARCHAR类型,会静默转成 0,导致全表没数据匹配 - 字段为
NULL时,NULL & 4结果是NULL,被当成假值过滤掉——这可能不是你想要的
实操建议:
- 始终确认
status是整型(TINYINT、SMALLINT或INTEGER) - 显式写成
status & 4 = 4,语义明确,也方便加函数索引(如 PostgreSQL 的CREATE INDEX ON users ((status & 4))) - 需要兼容
NULL状态时,补上OR status IS NULL或用COALESCE(status, 0) & 4 = 4
PostgreSQL / SQL Server 中&行为一致吗?
语法看着像,但类型约束更严:PostgreSQL 要求两个操作数都为整型,SQL Server 同样拒绝字符串参与位运算。
典型报错:
- PostgreSQL:
operator does not exist: text & integer - SQL Server:
Operand data type varchar is invalid for '&' operator
实操建议:
- 别依赖隐式转换,提前用
CAST(status AS INTEGER)或建表时就定死类型 - SQL Server 2022+ 提供了
BITAND()函数,但老版本仍只能用&;别误以为它和 Oracle 一样必须用函数 - 测试时用
SELECT pg_typeof(status)(PG)或SELECT SQL_VARIANT_PROPERTY(status, 'BaseType')(SQL Server)查实际类型
Oracle 和 SQLite 怎么写等效的“状态位筛选”?
Oracle 不支持 & 作为中缀运算符,SQLite 默认不提供位与操作符——硬写 status & 4 在这两个库会直接报错。
对应写法:
- Oracle 必须用
BITAND(status, 4) = 4,且status不能是CHAR或NUMBER带小数,否则报ORA-01722: invalid number - SQLite 用内置函数
bitand(status, 4) = 4(需启用ENABLE_BITOPS编译选项),否则得自己实现或改用status % 8 >= 4这类算术模拟(仅适用于单一位)
性能注意点:
- Oracle 的
BITAND()是标量函数,无法走普通 B-tree 索引;若高频查询某位,考虑加函数索引:CREATE INDEX idx_user_locked ON users (BITAND(status, 4)) - SQLite 的
bitand()在 3.35+ 才稳定,旧版本建议用整型字段 +status & 4配合编译参数开启
联合多个状态位时,&和OR混用为什么危险?
想查“已激活或已锁定”的用户,写成 status & (1 OR 4) = (1 OR 4) 是错的——OR 是逻辑或,不是位或,这里先算 1 OR 4 得到 TRUE(即 1),整个条件退化为 status & 1 = 1,只筛奇数 ID。
正确做法只有两种:
- 分开写:
(status & 1 = 1) OR (status & 4 = 4) - 用位或合并掩码:
status & (1 | 4) != 0(注意是!= 0,不是= (1 | 4))
容易被忽略的地方:
- 位或掩码值必须是 2 的幂之和(如
1|2|4|8),不能写status & 6 = 6来表示“第 1 位和第 2 位同时为 1”,因为 6 的二进制是110,它要求第 2 位为 1、第 1 位为 1、第 0 位为 0,语义完全不同 - MySQL 对大整数(如
BIGINT)做位运算时,确保客户端和服务器都启用了sql_mode中的NO_UNSIGNED_SUBTRACTION,否则~取反可能溢出

















