WHERE子句必须紧接FROM之后且仅出现一次,多条件用AND/OR连接并注意优先级,字符串用单引号,NULL用IS NULL判断,数值、日期、文本需按类型正确比较。

WHERE子句的基本写法和常见错误
WHERE 子句不是可选的装饰,而是过滤逻辑的实际执行点。漏写 WHERE 或把条件写在 SELECT 后面(比如 SELECT * FROM users WHERE 后直接跟 ORDER BY)会导致语法错误或全表扫描。
- 必须紧接在
FROM子句之后,且只能出现一次 - 多个条件用
AND/OR连接,注意运算优先级:AND优先于OR,不确定时加括号,比如(status = 'active' OR status = 'pending') AND created_at > '2024-01-01' - 字符串值必须用单引号包裹,
WHERE name = "John"是错的,应写成WHERE name = 'John' -
NULL不能用=判断,得用IS NULL或IS NOT NULL;WHERE score = NULL永远不返回任何行
数值、日期、文本字段的典型过滤场景
不同数据类型对应的比较方式差异很大,写错一个符号或格式就查不到数据。
- 数值字段:直接比较,
WHERE price > 99.99;但要注意隐式转换风险,比如WHERE user_id = '123'在某些数据库里会触发类型转换,可能影响索引使用 - 日期字段:推荐用标准格式
'2024-03-15',避免'15/03/2024'这类区域相关写法;时间范围建议用BETWEEN(注意它包含边界),或更安全的created_at >= '2024-01-01' AND created_at - 文本字段:模糊匹配用
LIKE,但LIKE '%keyword%'无法走索引;前缀匹配LIKE 'prefix%'才可能命中索引;大小写敏感取决于数据库配置,MySQL 默认不区分,PostgreSQL 区分,需要时用ILIKE(PostgreSQL)或LOWER(name) LIKE LOWER('%john%')
WHERE中使用子查询或函数的性能陷阱
WHERE 里嵌套子查询或函数看似方便,但极易拖慢查询,尤其在大表上。
-
WHERE id IN (SELECT user_id FROM logs WHERE action = 'login')可能产生重复执行,改用JOIN或EXISTS更高效 - 对字段用函数会阻止索引使用,比如
WHERE YEAR(created_at) = 2024无法利用created_at索引;应改写为WHERE created_at >= '2024-01-01' AND created_at -
WHERE status IN ('active', 'pending', 'draft')比多个OR更清晰,但值太多(比如几百个)时,部分数据库会退化,此时考虑临时表或应用层拆分
WHERE与NULL、空字符串、默认值的纠缠
业务里最常出问题的地方不是语法,而是对“空”的理解混乱——数据库里的 NULL、空字符串 ''、数字零 0、默认值 'N/A' 全是不同语义,混在一起过滤就会漏数据。
- 检查字段是否允许
NULL(看表结构),再决定用IS NULL还是= '' - 不要假设
status != 'inactive'就等于 “是 active”,因为NULL和其他值也会被包含进来;明确写出status IN ('active', 'pending') - 如果字段有默认值(比如
status DEFAULT 'unknown'),记得把它也纳入过滤条件,否则WHERE status = 'active'会漏掉那些没显式设置、靠默认值撑着的记录
实际跑查询前,先用 EXPLAIN 看执行计划,重点确认 type 是否为 ref 或 range,key 是否用了预期索引——很多“WHERE 不生效”的抱怨,其实只是没走索引而已。

















