跳到主要内容

WHERE 条件

WHERE 子句用于过滤记录,只返回满足条件的行。本章将详细介绍 WHERE 的各种用法。

基本 WHERE

比较运算符

WHERE 支持以下比较运算符:

运算符含义示例
=等于age = 18
<>!=不等于age != 18
>大于age > 18
<小于age < 18
>=大于等于age >= 18
<=小于等于age <= 18
-- 查询年龄等于 18 的用户
SELECT * FROM users WHERE age = 18;

-- 查询年龄大于 18 的用户
SELECT * FROM users WHERE age > 18;

-- 查询城市不是北京的用户
SELECT * FROM users WHERE city != '北京';

字符串比较

字符串需要用单引号包裹:

-- 精确匹配
SELECT * FROM users WHERE name = '张三';

-- 字符串比较按字典顺序
SELECT * FROM products WHERE name < 'C';

日期比较

日期也需要用单引号包裹:

-- 查询特定日期
SELECT * FROM orders WHERE order_date = '2024-01-01';

-- 查询日期范围
SELECT * FROM orders WHERE order_date > '2024-01-01';
SELECT * FROM orders WHERE order_date BETWEEN '2024-01-01' AND '2024-12-31';

逻辑运算符

AND 与运算

所有条件都为真时返回 true:

-- 查询年龄大于 18 且城市为北京的用户
SELECT * FROM users
WHERE age > 18 AND city = '北京';

-- 多个 AND 条件
SELECT * FROM products
WHERE category = '电子产品'
AND price > 1000
AND stock > 0;

OR 或运算

任一条件为真时返回 true:

-- 查询城市为北京或上海的用户
SELECT * FROM users
WHERE city = '北京' OR city = '上海';

-- 查询特定状态
SELECT * FROM orders
WHERE status = 'pending' OR status = 'processing';

NOT 非运算

取反条件:

-- 查询不是北京的用户
SELECT * FROM users WHERE NOT city = '北京';

-- 查询不等于特定值
SELECT * FROM products WHERE NOT category = '电子产品';

运算符优先级

AND 的优先级高于 OR:

-- 这条语句的执行顺序
SELECT * FROM users
WHERE city = '北京' AND age > 18 OR status = 'vip';

-- 等价于
SELECT * FROM users
WHERE (city = '北京' AND age > 18) OR status = 'vip';

-- 如果需要不同的逻辑,使用括号
SELECT * FROM users
WHERE city = '北京' AND (age > 18 OR status = 'vip');

BETWEEN 范围查询

BETWEEN 用于查询范围内的值,包含边界:

-- 查询价格在 100 到 500 之间的产品
SELECT * FROM products
WHERE price BETWEEN 100 AND 500;

-- 等价于
SELECT * FROM products
WHERE price >= 100 AND price <= 500;

-- 日期范围
SELECT * FROM orders
WHERE order_date BETWEEN '2024-01-01' AND '2024-12-31';

-- NOT BETWEEN
SELECT * FROM products
WHERE price NOT BETWEEN 100 AND 500;
注意

BETWEEN 包含边界值,即 BETWEEN 100 AND 500 等价于 >= 100 AND <= 500

IN 列表查询

IN 用于匹配多个值中的一个:

-- 查询城市为北京、上海或广州的用户
SELECT * FROM users
WHERE city IN ('北京', '上海', '广州');

-- 等价于
SELECT * FROM users
WHERE city = '北京' OR city = '上海' OR city = '广州';

-- NOT IN
SELECT * FROM users
WHERE city NOT IN ('北京', '上海', '广州');

-- 子查询
SELECT * FROM orders
WHERE user_id IN (SELECT id FROM users WHERE status = 'active');

IN 的优点:

  • 语法简洁,易于阅读
  • 性能通常优于多个 OR
  • 支持子查询

LIKE 模糊匹配

LIKE 用于模糊匹配字符串,支持通配符:

通配符

通配符含义
%匹配任意数量的字符(包括零个)
_匹配单个字符
-- 以"张"开头
SELECT * FROM users WHERE name LIKE '张%';

-- 以"三"结尾
SELECT * FROM users WHERE name LIKE '%三';

-- 包含"小"
SELECT * FROM users WHERE name LIKE '%小%';

-- 第二个字符是"三"
SELECT * FROM users WHERE name LIKE '_三%';

-- 正好三个字符
SELECT * FROM users WHERE name LIKE '___';

NOT LIKE

排除匹配的记录:

-- 查询邮箱不是以 @gmail.com 结尾的用户
SELECT * FROM users WHERE email NOT LIKE '%@gmail.com';

转义通配符

如果需要匹配 %_ 本身,使用转义:

-- 查询包含 % 的产品名
SELECT * FROM products WHERE name LIKE '%\%%';

-- 使用自定义转义字符
SELECT * FROM products WHERE name LIKE '%|%%' ESCAPE '|';

NULL 处理

NULL 需要使用特殊的比较方式:

-- 错误:NULL 不能用 = 比较
SELECT * FROM users WHERE phone = NULL; -- 不会返回任何结果

-- 正确:使用 IS NULL
SELECT * FROM users WHERE phone IS NULL;

-- 查询非 NULL 值
SELECT * FROM users WHERE phone IS NOT NULL;

-- 组合条件
SELECT * FROM users
WHERE phone IS NOT NULL AND city = '北京';
重要

NULL 与任何值的比较都返回 NULL(不是 true 或 false),所以必须使用 IS NULLIS NOT NULL

复杂条件组合

多条件组合

-- 复杂的业务查询
SELECT * FROM orders
WHERE status = 'completed'
AND total_amount > 1000
AND (payment_method = 'credit_card' OR payment_method = 'alipay')
AND created_at BETWEEN '2024-01-01' AND '2024-12-31';

使用括号控制逻辑

-- 查询 VIP 用户或者(北京地区且年龄大于 18 的用户)
SELECT * FROM users
WHERE status = 'vip'
OR (city = '北京' AND age > 18);

-- 查询(VIP 用户或北京地区)且年龄大于 18 的用户
SELECT * FROM users
WHERE (status = 'vip' OR city = '北京')
AND age > 18;

性能优化建议

1. 使用索引友好的条件

-- 好:可以使用索引
SELECT * FROM users WHERE city = '北京';

-- 差:无法使用索引(以通配符开头)
SELECT * FROM users WHERE name LIKE '%张%';

-- 好:可以使用索引
SELECT * FROM users WHERE name LIKE '张%';

2. 避免在 WHERE 中使用函数

-- 差:索引失效
SELECT * FROM users WHERE YEAR(created_at) = 2024;

-- 好:使用范围查询
SELECT * FROM users
WHERE created_at >= '2024-01-01'
AND created_at < '2025-01-01';

3. 避免隐式类型转换

-- 差:字符串与数字比较(隐式转换)
SELECT * FROM users WHERE phone = 13800138000;

-- 好:类型匹配
SELECT * FROM users WHERE phone = '13800138000';

小结

本章我们学习了:

  1. 比较运算符(=<>><>=<=
  2. 逻辑运算符(ANDORNOT
  3. BETWEEN 范围查询
  4. IN 列表查询
  5. LIKE 模糊匹配
  6. NULL 值处理
  7. 复杂条件组合
  8. 性能优化建议

练习

  1. 查询价格大于 100 且库存大于 0 的产品
  2. 查询城市为北京、上海或广州的用户
  3. 查询姓名以"张"开头的用户
  4. 查询邮箱为 NULL 的用户
  5. 查询 2024 年 1 月到 3 月的订单