WHERE子句通过布尔表达式筛选行,AND表示同时满足,OR表示满足其一;混合时AND优先级更高,多条件须加括号;IN仅适用于单字段多值匹配;NULL参与比较结果为UNKNOWN,需用IS NULL/NOT NULL显式处理。

WHERE 子句本身不支持“多条件筛选”这个模糊说法——它只做一件事:对每一行求一个布尔表达式,返回 TRUE 的才保留。所谓“精准”,取决于你写的逻辑是否真对应业务意图,而不是堆条件。
AND 和 OR 到底怎么选?看语义,不是看数量
写错 AND/OR 是最常见、最隐蔽的错误。结果不是报错,而是查不到数据,或查出一堆不该出现的行。
-
AND表示“同时满足”:比如status = 'active' AND created_at >= '2026-01-01',缺一不可 -
OR表示“满足其一即可”:比如country = 'CN' OR country = 'US',任一匹配就过 - 混合时,
AND优先级永远高于OR。写WHERE a = 1 OR b = 2 AND c = 3等价于WHERE a = 1 OR (b = 2 AND c = 3),不是你想的(a = 1 OR b = 2) AND c = 3 - 所有
OR组合必须加括号显式包裹,例如:WHERE (type = 'vip' OR type = 'trial') AND status = 'active'
IN 不是万能的,别硬套多字段约束
IN 只适合单字段匹配多个离散值。想表达“国家是 CN 或 US 或 JP”,用 country IN ('CN', 'US', 'JP') 没问题;但想表达“国家是 CN 且订单金额 > 100”,就不能写成 country IN ('CN') AND amount IN (101, 102, ...)——这不是错,是可读性灾难,也难维护。
- 多字段组合约束,必须用
AND(交集)或OR(并集),不能靠IN拆解 -
IN列表里如果混入NULL,整个条件变成UNKNOWN,该行被过滤掉(静默失效) - 子查询做右值时,必须只返回一列:
id IN (SELECT user_id FROM logs WHERE action = 'login')✅;id IN (SELECT user_id, created_at FROM logs)❌(报错:subquery returns more than one column)
NULL 值会让所有比较失效,必须单独处理
SQL 用三值逻辑:TRUE/FALSE/UNKNOWN。任何字段与 NULL 的比较(=、!=、>、IN、NOT IN)都返回 UNKNOWN,而 WHERE 只认 TRUE。
- 查非空邮箱,不能只写
email != '',因为email IS NULL的行也会被漏掉;得写email IS NOT NULL AND email != '' - 想统一排除
NULL和空字符串,用COALESCE(email, '') != ''更简洁 -
NOT IN遇到子查询含任意NULL,整条条件恒为UNKNOWN,结果集为空——线上最难复现的 bug 之一,务必改用NOT EXISTS
复杂分支逻辑,别硬塞进 WHERE,先拆再合
比如业务规则:“当 type = 1 且 item = 1 时,只允许 product = 4;其余情况全部放行”。这不是靠 AND/OR 直接堆出来的,而是三条互斥规则的并集:
- 规则1(精确):
type = 1 AND item = 1 AND product = 4 - 规则2(宽松):
item != 1 - 规则3(宽松):
type != 1
最终写成:WHERE (type = 1 AND item = 1 AND product = 4) OR (item != 1) OR (type != 1)。注意括号不能省,顺序无关,但语义必须覆盖全集。
这种结构在 Laravel 等 ORM 中可用链式构建,避免手拼 SQL 出错;真实场景中若分支更多,建议用 WITH 先拆解各条件集,再 JOIN 或 IN 组合——可读性比一行长条件重要得多。
最容易被忽略的是:括号缺失、NULL 静默吞掉数据、以及把“业务上的‘或者’”直接翻译成 OR 而没验证逻辑覆盖是否完整。

















