Skip to content

WHERE 过滤:比较、逻辑与 NULL ​

WHERE 子句基础 ​

WHERE 子句用于过滤行,只返回满足条件的数据。

基本语法:

sql
SELECT columns
FROM table
WHERE condition;

示例:查询年龄大于 30 的用户

sql
SELECT name, age FROM users WHERE age > 30;

结果:

text
  name   | age
---------+-----
 Charlie |  35

执行顺序:FROM → WHERE → SELECT

这解释了为什么 WHERE 中不能使用 SELECT 中定义的列别名:

sql
-- 错误:WHERE 执行时还没有 user_age 别名
SELECT name, age AS user_age 
FROM users 
WHERE user_age > 30;

正确写法:

sql
SELECT name, age AS user_age 
FROM users 
WHERE age > 30;  -- 使用原列名

比较运算符 ​

运算符含义示例
=等于age = 25
!= 或 <>不等于age != 25
>大于age > 30
>=大于等于age >= 30
<小于age < 30
<=小于等于age <= 30

示例:

sql
-- 查询年龄正好是 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;

字符串比较 ​

字符串使用单引号:

sql
SELECT name, email FROM users WHERE name = 'Alice';

结果:

text
 name  |       email
-------+-------------------
 Alice | alice@example.com

字符串比较区分大小写(PostgreSQL 默认):

sql
SELECT name FROM users WHERE name = 'alice';  -- 找不到,因为是 'Alice'

不区分大小写的比较:

sql
-- PostgreSQL
SELECT name FROM users WHERE LOWER(name) = LOWER('alice');

-- 或使用 ILIKE(PostgreSQL 特有)
SELECT name FROM users WHERE name ILIKE 'alice';

逻辑运算符 ​

AND:所有条件都必须满足 ​

sql
SELECT name, age FROM users WHERE age > 25 AND age < 35;

结果:

text
 name  | age
-------+-----
 Alice |  30
 Diana |  28

OR:至少一个条件满足 ​

sql
SELECT name, age FROM users WHERE age < 26 OR age > 33;

结果:

text
  name   | age
---------+-----
 Bob     |  25
 Charlie |  35

NOT:条件取反 ​

sql
SELECT name, age FROM users WHERE NOT (age > 30);

等价于:

sql
SELECT name, age FROM users WHERE age <= 30;

组合逻辑:使用括号 ​

括号控制运算优先级(AND 优先级高于 OR):

sql
-- 不使用括号:(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 不等于任何值 ​

sql
-- 错误:这不会返回 Eve(age 是 NULL)
SELECT name, age FROM users WHERE age = NULL;

结果:空(0 行)

为什么?因为 NULL = NULL 的结果是 NULL(未知),而 WHERE 只返回结果为 TRUE 的行。

正确检查 NULL:IS NULL 和 IS NOT NULL ​

sql
-- 查询年龄为 NULL 的用户
SELECT name, age FROM users WHERE age IS NULL;

结果:

text
 name | age
------+-----
 Eve  |
sql
-- 查询年龄不为 NULL 的用户
SELECT name, age FROM users WHERE age IS NOT NULL;

结果:

text
  name   | age
---------+-----
 Alice   |  30
 Bob     |  25
 Charlie |  35
 Diana   |  28

NULL 参与运算 ​

任何对 NULL 的算术或比较运算结果都是 NULL:

sql
SELECT 
    name,
    age,
    age > 30 AS is_over_30,
    age + 5 AS age_plus_5
FROM users;

结果:

text
  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:范围查询 ​

sql
SELECT name, age FROM users WHERE age BETWEEN 25 AND 30;

等价于:

sql
SELECT name, age FROM users WHERE age >= 25 AND age <= 30;

结果:

text
 name  | age
-------+-----
 Alice |  30
 Bob   |  25
 Diana |  28

注意:BETWEEN 是闭区间(包含边界)。

排除 BETWEEN:

sql
SELECT name, age FROM users WHERE age NOT BETWEEN 25 AND 30;

IN:集合成员检查 ​

sql
SELECT name, age FROM users WHERE age IN (25, 30, 35);

结果:

text
  name   | age
---------+-----
 Alice   |  30
 Bob     |  25
 Charlie |  35

等价于:

sql
SELECT name, age FROM users WHERE age = 25 OR age = 30 OR age = 35;

排除 IN:

sql
SELECT name, age FROM users WHERE age NOT IN (25, 30, 35);

字符串也可以用 IN:

sql
SELECT name FROM users WHERE name IN ('Alice', 'Bob', 'Charlie');

注意:如果 IN 列表中有 NULL,NOT IN 可能返回意外结果(后续章节详细讨论)。

LIKE:模式匹配 ​

通配符 ​

  • %:匹配任意数量的字符(包括零个)
  • _:匹配恰好一个字符

示例:

sql
-- 查询姓名以 'A' 开头的用户
SELECT name FROM users WHERE name LIKE 'A%';

结果:

text
 name
-------
 Alice
sql
-- 查询姓名包含 'li' 的用户
SELECT name FROM users WHERE name LIKE '%li%';

结果:

text
 name
--------
 Alice
 Charlie
sql
-- 查询姓名正好 3 个字符的用户
SELECT name FROM users WHERE name LIKE '___';

结果:

text
 name
------
 Bob
 Eve

不区分大小写的 LIKE ​

PostgreSQL 使用 ILIKE:

sql
SELECT name FROM users WHERE name ILIKE 'alice';  -- 找到 'Alice'

MySQL 的 LIKE 默认不区分大小写(取决于排序规则):

sql
SELECT name FROM users WHERE name LIKE 'alice';  -- 找到 'Alice'

区分大小写(MySQL):

sql
SELECT name FROM users WHERE name LIKE BINARY 'Alice';

转义特殊字符 ​

如果要匹配 % 或 _ 本身,使用反斜杠转义:

sql
-- 查询邮箱包含 '_' 的用户(假设数据中有)
SELECT email FROM users WHERE email LIKE '%\_%';

练习 ​

使用 users 表完成以下练习:

  1. 简单过滤:查询年龄大于等于 30 的所有用户。

  2. 范围查询:查询年龄在 25 到 30 之间(含)的用户。

  3. 逻辑组合:查询年龄小于 26 或大于 32 的用户。

  4. NULL 处理:查询年龄为 NULL 的用户,以及年龄不为 NULL 的用户(两个查询)。

  5. IN 操作:查询姓名为 'Alice'、'Bob' 或 'Diana' 的用户。

  6. 模式匹配:查询姓名以 'C' 开头的用户。

  7. 复杂条件:查询满足以下条件的用户:

    • 年龄在 25 到 35 之间,且
    • 姓名包含字母 'a'(不区分大小写)
  8. 边界测试:创建一个查询,查找年龄不在 25 到 30 之间的用户(不包括 NULL)。

完成练习后,打开本章答案页核对。

常见错误 ​

错误 1:用 = NULL 检查空值 ​

sql
-- 错误
SELECT name FROM users WHERE age = NULL;

-- 正确
SELECT name FROM users WHERE age IS NULL;

错误 2:字符串用双引号 ​

sql
-- 错误(双引号是标识符)
SELECT name FROM users WHERE name = "Alice";

-- 正确(单引号是字符串字面量)
SELECT name FROM users WHERE name = 'Alice';

错误 3:忘记 NOT IN 中的 NULL 陷阱 ​

sql
-- 如果列表中有 NULL,结果可能为空
SELECT name FROM users WHERE age NOT IN (25, 30, NULL);
-- 返回 0 行,因为 age != NULL 总是返回 NULL

下一步 ​

学会了 WHERE 过滤。下一节学习 ORDER BY 和 LIMIT:如何对结果排序和分页。

回到第一章概览 · 返回SQL 学习路线

用心记录每一步成长