WHERE 条件过滤
本教程共 50 篇 · 第 23 篇 · 更新于 2026-07-31 · 约 8 分钟阅读
23. WHERE 条件过滤
本节目标:学完你能用 WHERE 按条件筛行,会用 AND/OR/NOT 组合多个条件,懂得用括号控制优先级,也知道 NULL 要用 IS NULL 来判断,还能避开 = NULL 这个无声的坑。
查询返回的数据往往太多,WHERE 就是用来「按条件过滤、只留想要的那些行」的。它不仅能用在 SELECT,UPDATE、DELETE 里一样能用。
先准备点数据:
INSERT INTO users (username, email, age, created_at)
VALUES
('xiaoming', 'ming@example.com', 28, '2026-06-15'),
('xiaohong', 'hong@example.com', 22, '2026-07-10'),
('wangwu', NULL, 35, '2026-07-20'),
('zhaoliu', 'zhao@example.com', NULL, '2026-08-05');
比较运算符
WHERE 后面跟一个「布尔表达式」(结果为真或假),只保留结果为真的行。常用比较运算符:
| 运算符 | 含义 |
|---|---|
= | 等于 |
<> 或 != | 不等于 |
> >= | 大于 / 大于等于 |
< <= | 小于 / 小于等于 |
找出年龄大于等于 28 的用户:
SELECT username, age
FROM users
WHERE age >= 28;
<> 和 != 等价,下面两条效果一样:
SELECT username FROM users WHERE age <> 28;
SELECT username FROM users WHERE age != 28;
AND、OR、NOT
AND:多个条件都要满足。OR:满足其中一个即可。NOT:取反。
找出年龄大于等于 28「且」邮箱不为空的用户:
SELECT username, age
FROM users
WHERE age >= 28 AND email IS NOT NULL;
找出年龄小于 25「或」邮箱为空的:
SELECT username
FROM users
WHERE age < 25 OR email IS NULL;
NOT 否定一个条件,比如「年龄不小于 25」:
SELECT username FROM users WHERE NOT (age < 25);
运算符优先级
一个常踩的坑:在 SQL 里,AND 比 OR 绑定得更紧。看这条:
SELECT username FROM users
WHERE age < 25 OR age > 30 AND email IS NOT NULL;
它实际等价于 age < 25 OR (age > 30 AND email IS NOT NULL),而不是你以为的 (age < 25 OR age > 30) AND ...。
Warning条件一多,千万别靠记忆去猜优先级。用括号把你的真实意图写清楚,既不会出错,别人读起来也轻松。上面的例子写成下面这样最稳妥:
SELECT username FROM users
WHERE (age < 25 OR age > 30) AND email IS NOT NULL;
判断 NULL:用 IS NULL
NULL 表示「未知、没有值」,它不等于 0,也不等于空字符串。所以永远不要写 = NULL,那样查不出任何行。
正确写法:
-- 找邮箱为空的
SELECT username FROM users WHERE email IS NULL;
-- 找邮箱不为空的
SELECT username FROM users WHERE email IS NOT NULL;
Tip记住一句口诀:NULL 不是值,不能比较,只能「测」。测空用
IS NULL,测非空用IS NOT NULL。这是新手最容易写错的地方。
= NULL 的反面教材
下面这条很隐蔽,它不会报错,但永远返回 0 行:
SELECT username FROM users WHERE email = NULL;
因为 NULL = NULL 的结果不是「真」,而是「未知」,所以没有任何行被留下。这是个无声的 bug,排查起来很费劲。看到别人写 = NULL,第一时间改成 IS NULL。
WHERE 里用函数
WHERE 的条件不一定是直接比较列,也能用函数算出来再判断。比如找邮箱长度大于 10 的用户:
SELECT username, email
FROM users
WHERE length(email) > 10;
length() 返回字符数。类似的还有 upper()、lower() 等,后面函数章节会细讲。这里只要知道:WHERE 后面可以很灵活。
文本比较区分大小写
普通 = 比较字符串时是区分大小写的。下面这条查不到 xiaoming,因为大小写不一致:
SELECT username FROM users WHERE username = 'XIAOMING';
要忽略大小写匹配,后面章节会讲 ILIKE 和 lower(),这里先有个印象:= 对文本是「较真」的。
用 WHERE 按日期过滤
如果表里有时间列,也能直接按日期筛。比如只看 2026 年 7 月之后注册的用户:
SELECT username, created_at
FROM users
WHERE created_at >= '2026-07-01';
日期写法和插入时一样,用 'YYYY-MM-DD' 字符串即可,PostgreSQL 会自动按时间比较。
WHERE 不止用于 SELECT
前面几章提过,UPDATE 和 DELETE 里的 WHERE 完全同样的逻辑。随手两个例子复习一下:
-- 只改资深用户的订单状态
UPDATE orders
SET status = 'vip'
WHERE user_id IN (SELECT id FROM users WHERE age > 30);
-- 只删没有邮箱的用户
DELETE FROM users WHERE email IS NULL;
一个 WHERE,决定了「动哪些行」。不管是查、改还是删,套路都一样。
常见错误
- 写
= NULL:查不出数据还不报错,改成IS NULL。 - 忽略 AND/OR 优先级:条件复杂时一定加括号。
- 字符串忘了加引号:
WHERE username = xiaoming会被当成列名,报「列不存在」。文本要写'xiaoming'。 - 大小写不匹配:
=区分大小写,文本比对要一致。
组合条件的实战
多个条件叠起来很常见。比如「找出年龄介于 25 到 35 之间,且邮箱不为空」的用户:
SELECT username, age
FROM users
WHERE age >= 25
AND age <= 35
AND email IS NOT NULL;
再用 NOT 取反,找「不是(资深且留了邮箱)」的人:
SELECT username, age
FROM users
WHERE NOT (age >= 30 AND email IS NOT NULL);
括号在这里尤其重要:NOT 只否定括号里整体,不会漏到外面去。
比较时的隐式类型转换
PostgreSQL 有时会自动把字符串转成数字或日期,所以下面这样也能跑:
SELECT username FROM users WHERE age = '28';
'28' 是字符串,但 age 是整数,数据库帮你转了一下。不过我建议还是按列类型写值:age = 28。依赖隐式转换,一旦数据里混进非数字字符就会报错,而且代码可读性也差。
文本比对要加引号
WHERE 里写文本条件,值必须用单引号包起来:
-- 正确
SELECT username FROM users WHERE username = 'xiaoming';
-- 错误:没引号会被当成列名,报「列 xiaoming 不存在」
SELECT username FROM users WHERE username = xiaoming;
Tip文本值永远加单引号;列名、关键字不用引号。这个习惯能避开一大类「列不存在」的报错。
用 WHERE 过滤文本列
文本列(比如订单的 status)也能直接比较。比如找出所有已支付订单:
SELECT id, user_id, amount
FROM orders
WHERE status = 'paid';
文本值照样加单引号。注意它区分大小写,写 'Paid' 就匹配不到 'paid'。
按日期范围筛选
时间列可以用 >= 和 <= 框一个区间。比如看 2026 年 7 月注册的:
SELECT username, created_at
FROM users
WHERE created_at >= '2026-07-01'
AND created_at < '2026-08-01';
这里用「小于下个月 1 号」来包含整个 7 月,比「小于等于 7 月 31 日 23:59:59」更省心,也不容易漏掉秒数。
综合查询实例
把前面学的拼起来:找「年龄 25 到 35 之间、邮箱不为空、且不是 zhaoliu」的用户:
SELECT username, age
FROM users
WHERE age >= 25
AND age <= 35
AND email IS NOT NULL
AND NOT (username = 'zhaoliu')
ORDER BY age;
ORDER BY 是后面的排序章节内容,这里先露个脸:它决定结果按什么顺序排列。
用括号给条件分组
当条件变多,AND 和 OR 混用时,用括号把「一组」条件框起来,意思最清楚。比如「要么很年轻,要么很资深,且必须有邮箱」:
SELECT username, age
FROM users
WHERE (age < 18 OR age > 60)
AND email IS NOT NULL;
括号明确告诉数据库:先算括号里的「年轻或资深」,再和「有邮箱」做 AND。少写括号,数据库会按自己的优先级猜,结果常和你想要的不一样。
Tip写复杂 WHERE 时,先把它单独放到 SELECT 里跑一遍,确认筛出的行数符合预期,再套到 UPDATE 或 DELETE 上。把「查询」当「预演」,能少犯很多大错。
小结
- WHERE 跟一个布尔条件,只保留条件为真的行。
- 比较运算:
=、<>、>、>=、<、<=。 AND优先于OR,复杂条件一定加括号明确意图。NOT取反;NULL 用IS NULL/IS NOT NULL判断,别写= NULL。- WHERE 还能用函数、按日期过滤,并且同样适用于 UPDATE 和 DELETE。