首页 / PostgreSQL 入门教程 / WHERE 条件过滤

PostgreSQL 入门教程

WHERE 条件过滤

本教程共 50 篇 · 第 23 篇 · 更新于 2026-07-31 · 约 8 分钟阅读

PostgreSQLPostgreSQL 入门教程WHERE比较运算符AND OR NOTIS NULL

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 里,ANDOR 绑定得更紧。看这条:

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';

要忽略大小写匹配,后面章节会讲 ILIKElower(),这里先有个印象:= 对文本是「较真」的。

用 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 是后面的排序章节内容,这里先露个脸:它决定结果按什么顺序排列。

用括号给条件分组

当条件变多,ANDOR 混用时,用括号把「一组」条件框起来,意思最清楚。比如「要么很年轻,要么很资深,且必须有邮箱」:

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。