WHERE 过滤:比较、逻辑与 NULL
WHERE 子句基础
WHERE 子句用于过滤行,只返回满足条件的数据。
基本语法:
SELECT columns
FROM table
WHERE condition;示例:查询年龄大于 30 的用户
SELECT name, age FROM users WHERE age > 30;结果:
name | age
---------+-----
Charlie | 35执行顺序:FROM → WHERE → SELECT
这解释了为什么 WHERE 中不能使用 SELECT 中定义的列别名:
-- 错误:WHERE 执行时还没有 user_age 别名
SELECT name, age AS user_age
FROM users
WHERE user_age > 30;正确写法:
SELECT name, age AS user_age
FROM users
WHERE age > 30; -- 使用原列名比较运算符
| 运算符 | 含义 | 示例 |
|---|---|---|
= | 等于 | age = 25 |
!= 或 <> | 不等于 | age != 25 |
> | 大于 | age > 30 |
>= | 大于等于 | age >= 30 |
< | 小于 | age < 30 |
<= | 小于等于 | age <= 30 |
示例:
-- 查询年龄正好是 25 岁的用户
SELECT name, age FROM users WHERE age = 25;
-- 查询年龄不是 25 岁的用户
SELECT name, age FROM users WHERE age != 25;
-- 查询年龄在 25 到 30 之间(包含边界)
SELECT name, age FROM users WHERE age >= 25 AND age <= 30;字符串比较
字符串使用单引号:
SELECT name, email FROM users WHERE name = 'Alice';结果:
name | email
-------+-------------------
Alice | alice@example.com字符串比较区分大小写(PostgreSQL 默认):
SELECT name FROM users WHERE name = 'alice'; -- 找不到,因为是 'Alice'不区分大小写的比较:
-- PostgreSQL
SELECT name FROM users WHERE LOWER(name) = LOWER('alice');
-- 或使用 ILIKE(PostgreSQL 特有)
SELECT name FROM users WHERE name ILIKE 'alice';逻辑运算符
AND:所有条件都必须满足
SELECT name, age FROM users WHERE age > 25 AND age < 35;结果:
name | age
-------+-----
Alice | 30
Diana | 28OR:至少一个条件满足
SELECT name, age FROM users WHERE age < 26 OR age > 33;结果:
name | age
---------+-----
Bob | 25
Charlie | 35NOT:条件取反
SELECT name, age FROM users WHERE NOT (age > 30);等价于:
SELECT name, age FROM users WHERE age <= 30;组合逻辑:使用括号
括号控制运算优先级(AND 优先级高于 OR):
-- 不使用括号:(age < 26 OR age > 33) AND name LIKE 'B%'
-- 可能不是你想要的
SELECT name, age FROM users WHERE age < 26 OR age > 33 AND name LIKE 'B%';
-- 使用括号明确意图
SELECT name, age FROM users WHERE (age < 26 OR age > 33) AND name LIKE 'B%';NULL 处理:三值逻辑
NULL 不等于任何值
-- 错误:这不会返回 Eve(age 是 NULL)
SELECT name, age FROM users WHERE age = NULL;结果:空(0 行)
为什么?因为 NULL = NULL 的结果是 NULL(未知),而 WHERE 只返回结果为 TRUE 的行。
正确检查 NULL:IS NULL 和 IS NOT NULL
-- 查询年龄为 NULL 的用户
SELECT name, age FROM users WHERE age IS NULL;结果:
name | age
------+-----
Eve |-- 查询年龄不为 NULL 的用户
SELECT name, age FROM users WHERE age IS NOT NULL;结果:
name | age
---------+-----
Alice | 30
Bob | 25
Charlie | 35
Diana | 28NULL 参与运算
任何对 NULL 的算术或比较运算结果都是 NULL:
SELECT
name,
age,
age > 30 AS is_over_30,
age + 5 AS age_plus_5
FROM users;结果:
name | age | is_over_30 | age_plus_5
---------+-----+------------+------------
Alice | 30 | f | 35
Bob | 25 | f | 30
Charlie | 35 | t | 40
Diana | 28 | f | 33
Eve | | |Eve 的所有计算结果都是 NULL。
BETWEEN:范围查询
SELECT name, age FROM users WHERE age BETWEEN 25 AND 30;等价于:
SELECT name, age FROM users WHERE age >= 25 AND age <= 30;结果:
name | age
-------+-----
Alice | 30
Bob | 25
Diana | 28注意:BETWEEN 是闭区间(包含边界)。
排除 BETWEEN:
SELECT name, age FROM users WHERE age NOT BETWEEN 25 AND 30;IN:集合成员检查
SELECT name, age FROM users WHERE age IN (25, 30, 35);结果:
name | age
---------+-----
Alice | 30
Bob | 25
Charlie | 35等价于:
SELECT name, age FROM users WHERE age = 25 OR age = 30 OR age = 35;排除 IN:
SELECT name, age FROM users WHERE age NOT IN (25, 30, 35);字符串也可以用 IN:
SELECT name FROM users WHERE name IN ('Alice', 'Bob', 'Charlie');注意:如果 IN 列表中有 NULL,NOT IN 可能返回意外结果(后续章节详细讨论)。
LIKE:模式匹配
通配符
%:匹配任意数量的字符(包括零个)_:匹配恰好一个字符
示例:
-- 查询姓名以 'A' 开头的用户
SELECT name FROM users WHERE name LIKE 'A%';结果:
name
-------
Alice-- 查询姓名包含 'li' 的用户
SELECT name FROM users WHERE name LIKE '%li%';结果:
name
--------
Alice
Charlie-- 查询姓名正好 3 个字符的用户
SELECT name FROM users WHERE name LIKE '___';结果:
name
------
Bob
Eve不区分大小写的 LIKE
PostgreSQL 使用 ILIKE:
SELECT name FROM users WHERE name ILIKE 'alice'; -- 找到 'Alice'MySQL 的 LIKE 默认不区分大小写(取决于排序规则):
SELECT name FROM users WHERE name LIKE 'alice'; -- 找到 'Alice'区分大小写(MySQL):
SELECT name FROM users WHERE name LIKE BINARY 'Alice';转义特殊字符
如果要匹配 % 或 _ 本身,使用反斜杠转义:
-- 查询邮箱包含 '_' 的用户(假设数据中有)
SELECT email FROM users WHERE email LIKE '%\_%';练习
使用 users 表完成以下练习:
简单过滤:查询年龄大于等于 30 的所有用户。
范围查询:查询年龄在 25 到 30 之间(含)的用户。
逻辑组合:查询年龄小于 26 或大于 32 的用户。
NULL 处理:查询年龄为 NULL 的用户,以及年龄不为 NULL 的用户(两个查询)。
IN 操作:查询姓名为 'Alice'、'Bob' 或 'Diana' 的用户。
模式匹配:查询姓名以 'C' 开头的用户。
复杂条件:查询满足以下条件的用户:
- 年龄在 25 到 35 之间,且
- 姓名包含字母 'a'(不区分大小写)
边界测试:创建一个查询,查找年龄不在 25 到 30 之间的用户(不包括 NULL)。
完成练习后,打开本章答案页核对。
常见错误
错误 1:用 = NULL 检查空值
-- 错误
SELECT name FROM users WHERE age = NULL;
-- 正确
SELECT name FROM users WHERE age IS NULL;错误 2:字符串用双引号
-- 错误(双引号是标识符)
SELECT name FROM users WHERE name = "Alice";
-- 正确(单引号是字符串字面量)
SELECT name FROM users WHERE name = 'Alice';错误 3:忘记 NOT IN 中的 NULL 陷阱
-- 如果列表中有 NULL,结果可能为空
SELECT name FROM users WHERE age NOT IN (25, 30, NULL);
-- 返回 0 行,因为 age != NULL 总是返回 NULL下一步
学会了 WHERE 过滤。下一节学习 ORDER BY 和 LIMIT:如何对结果排序和分页。