MySQL: MySQL高级过滤与正则表达式查询
最后更新:2026-08-26
简单过滤不够用时,高级过滤让你精准定位数据。
本课深入讲解复杂条件组合和正则表达式。
graph TB
A[WHERE 条件组合] --> B[AND 逻辑与]
A --> C[OR 逻辑或]
A --> D[NOT 取反]
B --> E[多条件同时满足]
C --> F[满足任一条件]
A --> G[IN 列表匹配]
A --> H[BETWEEN 范围]
A --> I[LIKE 通配符]
A --> J[REGEXP 正则]
A --> K[EXISTS 子查询]
1. 你将学到
- AND/OR 条件组合
- IN/NOT IN 列表查询
- BETWEEN 范围查询
- LIKE 通配符匹配
- REGEXP 正则表达式
2. 一个搜索功能的真实故事
(1) 痛点:搜索不精准
用户搜索 "john",要求匹配:
- John Smith
- JOHNSON
- john@example.com
- O'john
简单的 LIKE '%john%' 只能匹配一种情况。
(2) REGEXP 的解法
SQL
SELECT * FROM users
WHERE first_name REGEXP '^john|john$|john'
OR email REGEXP 'john';
3. AND/OR 深入
▶ 示例:复杂条件组合
SQL
-- 查询:Engineering 或 Sales 部门,且工资 > 5000
SELECT * FROM employees
WHERE (department = 'Engineering' OR department = 'Sales')
AND salary > 5000;
-- 查询:工资 5000-8000,且不是 HR 部门
SELECT * FROM employees
WHERE salary BETWEEN 5000 AND 8000
AND department != 'HR';
-- 查询:入职 2024 年后,或工资 > 10000
SELECT * FROM employees
WHERE hire_date >= '2024-01-01' OR salary > 10000;
4. IN/NOT IN
▶ 示例:列表查询
SQL
-- IN 查询
SELECT * FROM products WHERE category_id IN (1, 3, 5, 7);
-- NOT IN 查询
SELECT * FROM products WHERE category_id NOT IN (2, 4, 6);
-- 子查询 IN
SELECT * FROM employees
WHERE department_id IN (SELECT id FROM departments WHERE location = 'Beijing');
-- NOT EXISTS 替代 NOT IN(性能更好)
SELECT * FROM customers c
WHERE NOT EXISTS (
SELECT 1 FROM orders o WHERE o.customer_id = c.id
);
5. BETWEEN 进阶
▶ 示例:范围查询
SQL
-- 数值范围
SELECT * FROM products WHERE price BETWEEN 100 AND 500;
-- 日期范围
SELECT * FROM orders WHERE order_date BETWEEN '2026-01-01' AND '2026-06-30';
-- 字符串范围
SELECT * FROM employees WHERE last_name BETWEEN 'A' AND 'M';
-- NOT BETWEEN
SELECT * FROM products WHERE price NOT BETWEEN 100 AND 500;
6. LIKE 通配符
▶ 示例:模糊匹配
SQL
-- % 匹配任意多个字符(包括 0 个)
SELECT * FROM users WHERE name LIKE 'J%'; -- J 开头
SELECT * FROM users WHERE name LIKE '%son'; -- son 结尾
SELECT * FROM users WHERE name LIKE '%john%'; -- 包含 john
-- _ 匹配恰好一个字符
SELECT * FROM users WHERE name LIKE 'J_hn'; -- J_hn(John, Johan)
-- 组合使用
SELECT * FROM users WHERE email LIKE '%@gmail.com';
-- ESCAPE 转义特殊字符
SELECT * FROM files WHERE name LIKE '%\_%' ESCAPE '\\'; -- 包含 _
SELECT * FROM files WHERE name LIKE '%%' ESCAPE '\\'; -- 包含 %
7. REGEXP 正则表达式
(1) 常用正则元字符
| 元字符 | 说明 | 示例 |
|---|---|---|
^ |
开头 | '^John' — John 开头 |
$ |
结尾 | 'son$' — son 结尾 |
. |
任意单字符 | 'J.hn' — John, Johan |
[...] |
字符集 | '[abc]' — a/b/c 之一 |
[^...] |
排除字符集 | [^abc] — 非 a/b/c |
* |
0 次或多次 | 'ab*' — a, ab, abb |
+ |
1 次或多次 | 'ab+' — ab, abb |
? |
0 次或 1 次 | 'ab?' — a, ab |
{n} |
恰好 n 次 | 'a{3}' — aaa |
{n,m} |
n 到 m 次 | 'a{2,4}' — aa~aaaa |
| |
或 | 'cat|dog' — cat 或 dog |
▶ 示例:REGEXP 查询
SQL
-- 以 J 或 j 开头
SELECT * FROM users WHERE first_name REGEXP '^[Jj]';
-- 包含数字
SELECT * FROM users WHERE username REGEXP '[0-9]';
-- 邮箱格式验证(简单)
SELECT * FROM users WHERE email REGEXP '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$';
-- 手机号格式(中国大陆)
SELECT * FROM users WHERE phone REGEXP '^1[3-9][0-9]{9}$';
-- 包含中文
SELECT * FROM users WHERE name REGEXP '[一-龥]';
▶ 示例:REGEXP vs LIKE
SQL
-- LIKE 只能前后匹配
SELECT * FROM users WHERE name LIKE '%john%'; -- 包含 john
-- REGEXP 可以精确控制
SELECT * FROM users WHERE name REGEXP '^john$'; -- 完全等于 john(不区分大小写)
SELECT * FROM users WHERE name REGEXP 'john|jane'; -- john 或 jane
SELECT * FROM users WHERE name REGEXP '^[A-Z]'; -- 大写字母开头
8. EXISTS 子查询
▶ 示例:EXISTS 用法
SQL
-- 查询有订单的客户
SELECT * FROM customers c
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id);
-- 查询没有订单的客户
SELECT * FROM customers c
WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id);
❓ 常见问题
Q LIKE '%keyword%' 能走索引吗?
A 前缀有
% 无法走索引,会全表扫描。大数据量考虑全文索引(FULLTEXT)。Q REGEXP 和 LIKE 哪个快?
A 通常 LIKE 更快(可以走索引)。REGEXP 更灵活但不能走索引(MySQL 8.0 部分支持)。
Q IN 和 OR 哪个性能好?
A 数据少时差不多。IN 列表很长时,MySQL 会优化为排序后二分查找,比 OR 快。
Q NOT IN 有 NULL 陷阱?
A 是的。
NOT IN (1, 2, NULL) 永远返回空,因为 NULL 参与比较结果为 NULL。用 NOT EXISTS 替代。📖 小节
- AND/OR 组合条件,用括号明确优先级
- IN/NOT IN 列表查询,注意 NULL 陷阱
- BETWEEN 范围查询,包含两端值
- LIKE 通配符:
%任意多字符,_单个字符 - REGEXP 正则表达式,支持复杂模式匹配
- EXISTS 子查询存在性检查,性能通常优于 IN
📝 作业
-
基础题(难度⭐):用 LIKE 查询邮箱包含 '@gmail.com' 且用户名以 'J' 开头的用户。
-
进阶题(难度⭐⭐):用 REGEXP 查询中国大陆手机号(1 开头,第二位 3-9,共 11 位)。
-
挑战题(难度⭐⭐⭐):对比 NOT IN 和 NOT EXISTS 在包含 NULL 值时的查询结果差异。