WHERE 条件与运算符
本教程共 46 篇 · 第 20 篇 · 更新于 2026-07-30 · 约 11 分钟阅读
20. WHERE 条件与运算符
本节目标:学会用 WHERE 子句给查询加过滤条件,掌握比较运算符、逻辑运算符(AND/OR/NOT)、范围与集合运算符(IN/BETWEEN)、NULL 判断(IS NULL),以及运算符优先级和 NULL 参与运算的坑。
20.1 WHERE 的作用
上一章学的 SELECT * FROM users 把所有行都查出来了。但实际工作中,你通常只要其中一部分数据—比如”年龄大于 25 的用户”、“状态为 paid 的订单”。
WHERE 就是干这个的,它跟在 FROM 后面,用来过滤行:
SELECT username, age
FROM users
WHERE age > 25;
只有 age 大于 25 的行才会出现在结果里。WHERE 条件不满足的行,直接被过滤掉。
20.2 比较运算符
最常用的条件就是比较大小。MySQL 支持的比较运算符:
| 运算符 | 含义 | 示例 |
|---|---|---|
= | 等于 | WHERE age = 25 |
!= 或 <> | 不等于 | WHERE age != 25 |
> | 大于 | WHERE age > 25 |
>= | 大于等于 | WHERE age >= 25 |
< | 小于 | WHERE age < 25 |
<= | 小于等于 | WHERE age <= 25 |
注意 SQL 里判断相等用单个 =,不是 ==。这是跟编程语言不一样的地方,新手容易写错。
-- 查状态为 paid 的订单
SELECT * FROM orders WHERE status = 'paid';
-- 查年龄不等于 25 的用户
SELECT * FROM users WHERE age <> 25;
-- 查金额大于 100 的订单
SELECT * FROM orders WHERE amount > 100;
Note字符串也可以比较大小,按字典序。
'a' < 'b','apple' < 'banana'。但实际开发中很少直接比较字符串大小,更多用 LIKE 模糊匹配(下一章讲)。
20.3 逻辑运算符:AND / OR / NOT
单个条件不够用时,用逻辑运算符组合多个条件。
AND:并且
AND 要求所有条件都满足:
-- 年龄大于 25 且状态为 paid 的订单
SELECT * FROM orders
WHERE amount > 100 AND status = 'paid';
两个条件都得满足,行才会被选中。
OR:或者
OR 只要满足一个条件就行:
-- 状态为 paid 或 refunded 的订单
SELECT * FROM orders
WHERE status = 'paid' OR status = 'refunded';
NOT:取反
NOT 对条件取反:
-- 状态不是 paid 的订单
SELECT * FROM orders
WHERE NOT status = 'paid';
-- 等价于
SELECT * FROM orders
WHERE status != 'paid';
优先级问题
AND 的优先级比 OR 高。这意味着:
WHERE age > 25 AND username = '张三' OR username = '李四'
实际执行的是:
WHERE (age > 25 AND username = '张三') OR username = '李四'
先算 AND,再算 OR。如果你想要的是”年龄大于 25,并且用户名是张三或李四”,得加括号:
WHERE age > 25 AND (username = '张三' OR username = '李四')
Warning混用 AND 和 OR 时,一定要加括号。别依赖默认优先级,哪怕你背得出来,你的同事不一定知道。加括号既是给数据库看的,也是给人看的。我之前排查过一个 bug,就是少了一对括号导致条件逻辑完全变了。
20.4 IN:在指定集合中
IN 用来判断一个值是否在一组值里面,比写一堆 OR 简洁得多:
-- 查状态为 paid、shipped 或 refunded 的订单
SELECT * FROM orders
WHERE status IN ('paid', 'shipped', 'refunded');
等价于:
SELECT * FROM orders
WHERE status = 'paid' OR status = 'shipped' OR status = 'refunded';
显然 IN 写法更短更清晰。
NOT IN 取反,查不在集合里的:
SELECT * FROM orders
WHERE status NOT IN ('paid', 'shipped', 'refunded');
Note
IN后面的列表里如果有NULL,结果可能出乎意料。NOT IN碰到 NULL 会导致整个查询返回空结果。这个坑后面讲 NULL 时详细说。
IN 还能跟子查询配合:
-- 查有订单的用户
SELECT * FROM users
WHERE id IN (SELECT user_id FROM orders);
子查询章节会详细讲这个用法。
20.5 BETWEEN:范围查询
BETWEEN 用来查某个范围内的值,包含边界:
-- 查年龄在 20 到 30 之间的用户(包含 20 和 30)
SELECT * FROM users
WHERE age BETWEEN 20 AND 30;
等价于:
SELECT * FROM users
WHERE age >= 20 AND age <= 30;
NOT BETWEEN 查范围外的:
SELECT * FROM users
WHERE age NOT BETWEEN 20 AND 30;
BETWEEN 对日期也特别好用:
-- 查 7 月份的订单
SELECT * FROM orders
WHERE created_at BETWEEN '2026-07-01 00:00:00' AND '2026-07-31 23:59:59';
Tip
BETWEEN是闭区间,包含两个边界值。这是跟某些编程语言里的范围判断不一样的地方(有些是前闭后开)。记住了:BETWEEN 两头的值都算在内。
20.6 IS NULL:判断空值
NULL 在 MySQL 里是个特殊的存在,它表示”没有值”或”未知值”。判断 NULL 不能用 =:
-- 错误写法:查不出任何结果
SELECT * FROM users WHERE email = NULL;
-- 正确写法
SELECT * FROM users WHERE email IS NULL;
判断非空用 IS NOT NULL:
SELECT * FROM users WHERE email IS NOT NULL;
Warning
WHERE email = NULL不会报错,但永远查不出结果。因为 NULL 跟任何值比较(包括另一个 NULL)结果都是 NULL,不是 true。这是 SQL 里最容易踩的坑之一。记住:判断 NULL 永远用 IS NULL / IS NOT NULL。
20.7 NULL 的特殊行为
NULL 在 MySQL 中有一套独特的规则,必须理解清楚:
NULL 参与运算
任何值跟 NULL 做运算,结果都是 NULL:
SELECT 100 + NULL; -- 结果:NULL
SELECT NULL = NULL; -- 结果:NULL(不是 1/true)
NULL 参与比较
NULL 跟任何值比较(=、>、<、!=),结果都是 NULL,不是 false:
SELECT * FROM users WHERE age > NULL; -- 查不出任何行
SELECT * FROM users WHERE age != NULL; -- 也查不出任何行
NOT IN 的 NULL 陷阱
-- 如果 orders 表里有 user_id 为 NULL 的行
SELECT * FROM users
WHERE id NOT IN (SELECT user_id FROM orders);
子查询结果里只要有一个 NULL,整个 NOT IN 就返回空。因为 id NOT IN (1, 2, NULL) 相当于 id != 1 AND id != 2 AND id != NULL,而 id != NULL 永远是 NULL,整个条件就废了。
Tip用
NOT IN配合子查询时,在子查询里加WHERE 列 IS NOT NULL过滤掉 NULL,能避免这个坑。或者干脆改用NOT EXISTS,后面章节会讲。
用 IFNULL 和 COALESCE 处理 NULL
如果某列可能有 NULL,查询时想给个默认值,用 IFNULL 或 COALESCE:
-- age 为 NULL 时显示 0
SELECT username, IFNULL(age, 0) AS age FROM users;
-- COALESCE 返回第一个非 NULL 的值
SELECT username, COALESCE(age, 0) AS age FROM users;
COALESCE 可以接受多个参数,返回第一个非 NULL 的:
SELECT COALESCE(NULL, NULL, email, '无邮箱') FROM users;
20.8 运算符优先级
当一条 WHERE 里有多种运算符时,MySQL 按优先级从高到低执行。常见的优先级:
| 优先级 | 运算符 |
|---|---|
| 高 | !(NOT) |
| 比较运算符(=, >, <, >=, <=, !=, IS, IN, BETWEEN, LIKE) | |
&&(AND) | |
| 低 | ||(OR) |
实际使用中,NOT 优先级最高,比较运算符次之,AND 再次,OR 最低。
-- NOT 先执行,然后比较,然后 AND,最后 OR
WHERE NOT status = 'deleted' AND age > 20 OR amount > 500
-- 等价于
WHERE (NOT status = 'deleted') AND (age > 20) OR (amount > 500)
Note别背优先级表,永远加括号。括号能让逻辑一目了然,也能避免优先级理解错误导致的 bug。这条建议适用于所有 SQL 编写场景。
20.9 WHERE 的限制
WHERE 里可以用的东西很灵活,但也有几个限制:
不能用列别名:因为 WHERE 在 SELECT 之前执行,别名还没生成。
-- 报错
SELECT amount * 0.9 AS 折后价 FROM orders WHERE 折后价 > 100;
-- 正确写法:在 WHERE 里重复表达式
SELECT amount * 0.9 AS 折后价 FROM orders WHERE amount * 0.9 > 100;
不能用聚合函数:聚合函数在 GROUP BY 阶段计算,WHERE 在分组之前执行。
-- 报错
SELECT status, COUNT(*) FROM orders WHERE COUNT(*) > 5 GROUP BY status;
-- 正确写法:用 HAVING(后面章节讲)
SELECT status, COUNT(*) FROM orders GROUP BY status HAVING COUNT(*) > 5;
20.10 小结
WHERE 是查询的灵魂,不会 WHERE 等于不会查询。核心记住几点:比较用 =<> 逻辑用 AND/OR/NOT、集合用 IN、范围用 BETWEEN、空值用 IS NULL。混用运算符时加括号,碰到 NULL 时格外小心。下一章学模糊查询,用 LIKE 和正则表达式匹配字符串模式。