SQL中WHERE同时含AND和OR时必须加括号,否则按NOT>AND>OR优先级执行,易导致逻辑错误;IN可替代多OR提升可读性与性能;NOT后复合条件、ON子句中的括号同样关键。

WHERE里同时出现AND和OR,不加括号就等于写错
SQL解析器严格按优先级执行:NOT > AND > OR。写WHERE status = 'active' OR role = 'admin' AND dept = 'tech',实际等价于WHERE status = 'active' OR (role = 'admin' AND dept = 'tech'),而不是你脑中想的(status = 'active' OR role = 'admin') AND dept = 'tech'。
常见错误现象:本想查“北京或上海的女性用户”,却漏括号写成city = '北京' OR city = '上海' AND gender = '女',结果所有gender = '女'的记录全被拉出来,不管城市是哪。
- 只要WHERE中同时出现
AND和OR,无论几处,一律手动加括号 - 按业务语义分组:比如“(状态是active或pending)且支付方式是alipay或wechat”,对应
(status = 'active' OR status = 'pending') AND (payment_method = 'alipay' OR payment_method = 'wechat') - 别指望缩进、换行或空格能改变逻辑——SQL引擎完全不认格式
用IN替代一长串OR,更安全也更高效
写WHERE status = 'active' OR status = 'pending' OR status = 'shipped' OR status = 'cancelled'不仅难读,还容易漏掉OR导致语法错误;更重要的是,某些数据库优化器面对大量OR时会放弃走索引,尤其当字段没建索引或发生隐式类型转换时。
实操建议:
- 三个及以上等值判断,直接改用
IN:WHERE status IN ('active', 'pending', 'shipped', 'cancelled') -
IN列表别超几百项:SQLite有编译限制,MySQL受max_allowed_packet约束;超量时拆查询或用临时表 -
IN对NULL免疫:WHERE id IN (1, 2, NULL)中NULL部分被静默忽略,如需匹配空值,必须单独补OR id IS NULL
NOT后面跟复合条件,括号漏一层就全错
NOT只否定紧挨着它的下一个表达式,不是整条条件。写WHERE NOT a = 1 OR b = 2,实际是WHERE (NOT a = 1) OR b = 2,意思是“a≠1 或 b=2”,而非你想表达的“a≠1 且 b≠2”。
容易踩的坑:
- 否定“任一成立”:写
NOT (a = 1 OR b = 2) - 否定“全部成立”:写
NOT (a = 1 AND b = 2) - 用
!=或替代NOT column = value仅适用于单值比较;对NULL无效,仍需IS NOT NULL - PostgreSQL中
NOT IN (1, 2, NULL)整条返回空结果——这是标准行为,不是bug,务必提前过滤NULL
ON子句里混用AND/OR,括号位置决定关联逻辑
外连接中,ON和WHERE里的括号影响的是关联时机和过滤范围,不是可有可无的装饰。例如左连接想保留所有用户,但只关联“状态有效且非测试账号”的订单,必须把复合条件放在ON里并加括号:
LEFT JOIN orders ON users.id = orders.user_id AND (orders.status = 'valid' AND orders.is_test = 0)
如果错写成WHERE (orders.status = 'valid' AND orders.is_test = 0),就会把没匹配上订单的用户也剔除,等效于内连接。
关键点:
-
ON中的括号控制“哪些行参与关联” -
WHERE中的括号控制“关联后保留哪些结果” - JOIN嵌套越深,括号越容易错位,建议用CTE或子查询拆解三层以上逻辑
OR混在AND里,不加括号的结果几乎肯定和你要的不一致——这不是数据库的问题,是你写的逻辑被优先级悄悄改写了。

















