🔍 MySQL WHERE 子句

WHERE 子句概述

WHERE 子句用于过滤记录,只返回满足指定条件的记录。它是 SQL 查询中最重要的部分之一,可以与 SELECT、UPDATE、DELETE 等语句配合使用。

基本比较操作符

等于和不等于

-- 等于 SELECT * FROM users WHERE age = 25; SELECT * FROM users WHERE city = 'Beijing'; SELECT * FROM users WHERE status = 'active'; -- 不等于 SELECT * FROM users WHERE age != 25; SELECT * FROM users WHERE age <> 25; -- 标准 SQL 语法 SELECT * FROM users WHERE city != 'Beijing'; -- 字符串比较(区分大小写) SELECT * FROM users WHERE username = 'John'; -- 不会匹配 'john' SELECT * FROM users WHERE LOWER(username) = 'john'; -- 不区分大小写

大小比较

-- 大于和小于 SELECT * FROM users WHERE age > 18; SELECT * FROM users WHERE age < 65; SELECT * FROM users WHERE salary >= 50000; SELECT * FROM users WHERE created_at <= '2024-01-01'; -- 日期比较 SELECT * FROM orders WHERE order_date > '2024-01-01'; SELECT * FROM orders WHERE created_at >= '2024-01-01 00:00:00'; SELECT * FROM orders WHERE created_at < NOW(); -- 数值范围查询 SELECT * FROM products WHERE price > 100 AND price < 500;

范围和列表操作符

BETWEEN 范围查询

-- 数值范围 SELECT * FROM users WHERE age BETWEEN 18 AND 65; SELECT * FROM products WHERE price BETWEEN 100 AND 500; -- 日期范围 SELECT * FROM orders WHERE order_date BETWEEN '2024-01-01' AND '2024-12-31'; SELECT * FROM logs WHERE created_at BETWEEN '2024-01-01 00:00:00' AND '2024-01-31 23:59:59'; -- NOT BETWEEN SELECT * FROM users WHERE age NOT BETWEEN 18 AND 65; -- 字符串范围(按字典序) SELECT * FROM users WHERE username BETWEEN 'A' AND 'M';

IN 列表查询

-- 基本 IN 查询 SELECT * FROM users WHERE city IN ('Beijing', 'Shanghai', 'Guangzhou'); SELECT * FROM products WHERE category_id IN (1, 2, 3, 5); SELECT * FROM orders WHERE status IN ('pending', 'processing', 'shipped'); -- NOT IN SELECT * FROM users WHERE city NOT IN ('Beijing', 'Shanghai'); SELECT * FROM products WHERE id NOT IN (1, 2, 3); -- IN 子查询 SELECT * FROM users WHERE id IN ( SELECT user_id FROM orders WHERE total_amount > 1000 ); -- 多列 IN(MySQL 5.7+) SELECT * FROM users WHERE (city, country) IN (('Beijing', 'China'), ('Tokyo', 'Japan'));

模式匹配

LIKE 模糊查询

-- 基本 LIKE 查询 SELECT * FROM users WHERE username LIKE 'john%'; -- 以 'john' 开头 SELECT * FROM users WHERE username LIKE '%smith'; -- 以 'smith' 结尾 SELECT * FROM users WHERE username LIKE '%admin%'; -- 包含 'admin' SELECT * FROM users WHERE username LIKE 'user_'; -- 'user' + 单个字符 -- 通配符说明 -- % : 匹配零个或多个字符 -- _ : 匹配单个字符 -- 复杂模式 SELECT * FROM products WHERE product_name LIKE 'iPhone%'; SELECT * FROM users WHERE email LIKE '%@gmail.com'; SELECT * FROM users WHERE phone LIKE '138________'; -- 138开头的11位手机号 -- NOT LIKE SELECT * FROM users WHERE email NOT LIKE '%@temp%'; -- 转义特殊字符 SELECT * FROM products WHERE description LIKE '%50\% off%'; -- 查找包含 "50% off" 的记录 SELECT * FROM files WHERE filename LIKE '%\_backup%'; -- 查找包含 "_backup" 的文件名

正则表达式 REGEXP

-- 基本正则表达式 SELECT * FROM users WHERE username REGEXP '^[a-zA-Z]+$'; -- 只包含字母 SELECT * FROM users WHERE email REGEXP '^[^@]+@[^@]+\.[^@]+$'; -- 基本邮箱格式 SELECT * FROM products WHERE product_code REGEXP '^[A-Z]{2}[0-9]{4}$'; -- 2个字母+4个数字 -- 常用正则模式 SELECT * FROM users WHERE phone REGEXP '^1[3-9][0-9]{9}$'; -- 中国手机号 SELECT * FROM users WHERE username REGEXP '^[a-z0-9_]{3,20}$'; -- 用户名格式 SELECT * FROM products WHERE price REGEXP '^[0-9]+\.[0-9]{2}$'; -- 价格格式 -- NOT REGEXP SELECT * FROM users WHERE username NOT REGEXP '[0-9]'; -- 不包含数字的用户名 -- 大小写不敏感匹配 SELECT * FROM users WHERE username REGEXP BINARY '^Admin'; -- 区分大小写 SELECT * FROM users WHERE username REGEXP '^admin'; -- 不区分大小写(默认)

NULL 值处理

IS NULL 和 IS NOT NULL

-- 查找 NULL 值 SELECT * FROM users WHERE last_login IS NULL; SELECT * FROM products WHERE description IS NULL; SELECT * FROM orders WHERE delivery_date IS NULL; -- 查找非 NULL 值 SELECT * FROM users WHERE last_login IS NOT NULL; SELECT * FROM products WHERE description IS NOT NULL; -- 注意:不能使用 = NULL 或 != NULL -- 错误写法 SELECT * FROM users WHERE last_login = NULL; -- 永远返回空结果 SELECT * FROM users WHERE last_login != NULL; -- 永远返回空结果 -- 正确写法 SELECT * FROM users WHERE last_login IS NULL; SELECT * FROM users WHERE last_login IS NOT NULL;

NULL 值的特殊处理

-- 使用 COALESCE 处理 NULL SELECT username, COALESCE(last_login, '从未登录') AS last_login_display FROM users; -- 使用 IFNULL 处理 NULL SELECT product_name, IFNULL(description, '暂无描述') AS description_display FROM products; -- 使用 CASE 处理 NULL SELECT username, CASE WHEN last_login IS NULL THEN '从未登录' ELSE DATE_FORMAT(last_login, '%Y-%m-%d') END AS login_status FROM users; -- NULL 值在比较中的行为 SELECT * FROM users WHERE age > 25 OR age IS NULL; -- 包含 NULL 值 SELECT * FROM users WHERE NOT (age <= 25); -- 不包含 NULL 值

逻辑操作符

AND 逻辑与

-- 基本 AND 操作 SELECT * FROM users WHERE age >= 18 AND age <= 65; SELECT * FROM users WHERE city = 'Beijing' AND status = 'active'; SELECT * FROM products WHERE price > 100 AND category_id = 1 AND stock_quantity > 0; -- 多条件组合 SELECT * FROM orders WHERE status = 'completed' AND total_amount > 500 AND created_at >= '2024-01-01' AND user_id IS NOT NULL; -- 复杂条件 SELECT * FROM users WHERE (age BETWEEN 25 AND 35) AND (city IN ('Beijing', 'Shanghai')) AND (salary > 80000);

OR 逻辑或

-- 基本 OR 操作 SELECT * FROM users WHERE city = 'Beijing' OR city = 'Shanghai'; SELECT * FROM products WHERE category_id = 1 OR category_id = 2; SELECT * FROM orders WHERE status = 'pending' OR status = 'processing'; -- OR 与 AND 的组合(注意优先级) SELECT * FROM users WHERE (city = 'Beijing' OR city = 'Shanghai') AND age > 25; -- 复杂 OR 条件 SELECT * FROM users WHERE (age < 18 OR age > 65) OR (status = 'inactive') OR (last_login < DATE_SUB(NOW(), INTERVAL 1 YEAR));

NOT 逻辑非

-- 基本 NOT 操作 SELECT * FROM users WHERE NOT (age < 18); SELECT * FROM users WHERE NOT (city = 'Beijing'); -- NOT 与其他操作符结合 SELECT * FROM users WHERE NOT (age BETWEEN 18 AND 65); SELECT * FROM users WHERE NOT (city IN ('Beijing', 'Shanghai')); SELECT * FROM users WHERE NOT (username LIKE 'admin%'); -- 复杂 NOT 条件 SELECT * FROM users WHERE NOT ( (city = 'Beijing' AND age < 30) OR (city = 'Shanghai' AND salary < 50000) ); -- De Morgan's Law 应用 -- NOT (A AND B) = (NOT A) OR (NOT B) -- NOT (A OR B) = (NOT A) AND (NOT B) SELECT * FROM users WHERE NOT (age < 18 AND status = 'inactive'); -- 等价于 SELECT * FROM users WHERE age >= 18 OR status != 'inactive';

操作符优先级

📋 操作符优先级(从高到低)

  1. 括号 ()
  2. 比较操作符:=, !=, <>, <, <=, >, >=
  3. IS NULL, IS NOT NULL
  4. BETWEEN, IN, LIKE, REGEXP
  5. NOT
  6. AND
  7. OR
-- 优先级示例 -- 没有括号的情况 SELECT * FROM users WHERE city = 'Beijing' OR city = 'Shanghai' AND age > 25; -- 等价于 SELECT * FROM users WHERE city = 'Beijing' OR (city = 'Shanghai' AND age > 25); -- 使用括号明确优先级 SELECT * FROM users WHERE (city = 'Beijing' OR city = 'Shanghai') AND age > 25; -- 复杂条件的括号使用 SELECT * FROM orders WHERE (status = 'completed' OR status = 'shipped') AND (total_amount > 1000 OR (total_amount > 500 AND user_id IN (1,2,3))) AND created_at >= '2024-01-01';

子查询在 WHERE 中的应用

标量子查询

-- 与平均值比较 SELECT * FROM products WHERE price > (SELECT AVG(price) FROM products); -- 与最大值比较 SELECT * FROM users WHERE created_at = (SELECT MAX(created_at) FROM users); -- 相关子查询 SELECT * FROM products p1 WHERE price > ( SELECT AVG(price) FROM products p2 WHERE p2.category_id = p1.category_id );

EXISTS 子查询

-- 存在性检查 SELECT * FROM users u WHERE EXISTS ( SELECT 1 FROM orders o WHERE o.user_id = u.id AND o.status = 'completed' ); -- 不存在检查 SELECT * FROM products p WHERE NOT EXISTS ( SELECT 1 FROM order_items oi WHERE oi.product_id = p.id ); -- 复杂 EXISTS 查询 SELECT * FROM users u WHERE EXISTS ( SELECT 1 FROM orders o WHERE o.user_id = u.id AND o.created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) AND o.total_amount > 500 );

性能优化技巧

🚀 WHERE 子句性能优化

-- 性能优化示例 -- 不好的查询(在列上使用函数) SELECT * FROM orders WHERE YEAR(created_at) = 2024; -- 优化后的查询(使用范围条件) SELECT * FROM orders WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01'; -- 不好的查询(复杂的 OR 条件) SELECT * FROM users WHERE city = 'Beijing' OR city = 'Shanghai' OR city = 'Guangzhou'; -- 优化后的查询(使用 IN) SELECT * FROM users WHERE city IN ('Beijing', 'Shanghai', 'Guangzhou'); -- 使用复合索引的查询 SELECT * FROM orders WHERE user_id = 123 AND status = 'completed' AND created_at >= '2024-01-01'; -- 需要在 (user_id, status, created_at) 上创建复合索引

实际应用示例

电商业务查询

-- 查找活跃用户 SELECT * FROM users WHERE status = 'active' AND last_login >= DATE_SUB(NOW(), INTERVAL 30 DAY) AND email IS NOT NULL AND email NOT LIKE '%@temp%'; -- 查找热销产品 SELECT p.* FROM products p WHERE p.status = 'active' AND p.stock_quantity > 0 AND EXISTS ( SELECT 1 FROM order_items oi JOIN orders o ON oi.order_id = o.id WHERE oi.product_id = p.id AND o.created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) AND o.status = 'completed' GROUP BY oi.product_id HAVING SUM(oi.quantity) > 100 ); -- 查找异常订单 SELECT * FROM orders WHERE ( (total_amount > 10000 AND user_id NOT IN (SELECT id FROM vip_users)) OR (total_amount < 1 AND status = 'completed') OR (created_at != updated_at AND status = 'pending' AND created_at < DATE_SUB(NOW(), INTERVAL 24 HOUR)) );

数据清理查询

-- 查找重复数据 SELECT email, COUNT(*) as count FROM users WHERE email IS NOT NULL GROUP BY email HAVING COUNT(*) > 1; -- 查找无效数据 SELECT * FROM users WHERE email NOT REGEXP '^[^@]+@[^@]+\.[^@]+$' OR phone NOT REGEXP '^1[3-9][0-9]{9}$' OR age < 0 OR age > 150 OR username IS NULL OR username = ''; -- 查找孤立数据 SELECT * FROM order_items oi WHERE NOT EXISTS ( SELECT 1 FROM orders o WHERE o.id = oi.order_id ) OR NOT EXISTS ( SELECT 1 FROM products p WHERE p.id = oi.product_id );

📋 WHERE 子句最佳实践

  1. 索引优化:为常用的 WHERE 条件列创建索引
  2. 条件顺序:将选择性高的条件放在前面
  3. 避免函数:不要在 WHERE 条件的列上使用函数
  4. NULL 处理:正确处理 NULL 值的比较
  5. 类型匹配:确保比较的数据类型一致
  6. 使用括号:复杂条件使用括号明确优先级
  7. 测试验证:复杂条件要充分测试各种情况