括号是SQL中逻辑运算优先级的强制约定,AND永远高于OR,混用时必须显式加括号,否则语义错位;格式化工具L017会报错,ORM需用闭包避免链式调用陷阱,复杂逻辑应拆分或用CTE/UNION ALL提升可维护性。

直接加括号,别信缩进、空格或“看着顺眼”——数据库只认括号,不读你的意图。
AND优先级永远高于OR,不加括号等于默认套了(B AND C)
写WHERE a = 1 OR b = 2 AND c = 3,数据库实际执行的是WHERE a = 1 OR (b = 2 AND c = 3),不是你脑中想的WHERE (a = 1 OR b = 2) AND c = 3。这个规则在 MySQL、PostgreSQL、SQL Server 全部一致,没法绕开。
- 人脑习惯按业务分组读,比如“北京用户或上海VIP用户”,但数据库先算
AND再算OR,两者天然错位 - 哪怕只混用一次
AND和OR,也必须显式加括号,这不是风格问题,是逻辑对齐的底线 - 格式化工具(如 sqlfluff)的 L017 规则会自动报这个错,CI 里建议直接接入
业务语义天然分组的地方,必须用括号包裹整组
查“华东已发货”或“所有已签收”的订单,不能写成region = '华东' AND status = '已发货' OR status = '已签收'——这会拉出所有status = '已签收'的记录,不管region是什么。
- 正确写法是:
WHERE (region = '华东' AND status = '已发货') OR status = '已签收' - 查“VIP且消费超5000”或“非VIP但复购≥3次”,必须拆成两组:
(is_vip = 1 AND amount > 5000) OR (is_vip = 0 AND repeat_count >= 3) - ORM 里链式调用容易翻车,比如 Laravel 的
where()->orWhere()->where()会生成无括号 SQL,务必改用闭包式where(function ($q) { ... })
嵌套三层以上括号时,人眼已不可靠,该拆就拆
像((a AND b) OR (c AND (d OR e)))这种结构,你自己下周回来看都可能不敢动。别硬堆,优先考虑可维护性。
- 用 CTE 提前定义子逻辑:
WITH active_users AS (SELECT * FROM t WHERE status = 'active'), vip_shanghai AS (SELECT * FROM t WHERE city = '上海' AND is_vip = true) - 或者拆成
UNION ALL:两个独立查询分别走索引,比一个带OR的大查询更可控 - 测试时一定要插
NULL值数据——column = 'X' OR column = 'Y'永远不匹配NULL行,得补OR column IS NULL才安全
括号不是语法装饰,是你和数据库之间关于“哪部分先算”的书面约定。漏一个,结果就偏;多一层嵌套,后续人踩坑概率就指数上升。

















