上一期我们把最基础的 INSERT / UPDATE / DELETE / SELECT 语法过了一遍,今天继续把 SELECT 这个最核心的操作深入展开,重点放在:
- WHERE 条件全家桶
- 模糊查询 & 比较运算
- 排序(ORDER BY)
- 分页(LIMIT / OFFSET)
- 简单聚合(COUNT / SUM / AVG / MAX / MIN)
- 去重(DISTINCT)
- 常用组合写法
这些内容几乎占了日常 SQL 开发的 70% 以上。
一、WHERE 条件常用运算符速查表
| 类别 | 运算符 | 示例 | 说明 / 注意事项 |
|---|---|---|---|
| 比较 | =, !=, <>, >, <, >=, <= | age > 18 | <> 和 != 等价,推荐用 <> |
| 范围 | BETWEEN … AND … | age BETWEEN 18 AND 35 | 包含边界 |
| 集合 | IN / NOT IN | city IN ('北京','上海','广州') | 比多个 OR 效率更高 |
| 空值 | IS NULL / IS NOT NULL | deleted_at IS NULL | 不能用 = NULL |
| 布尔 | IS TRUE / IS FALSE | is_active IS TRUE | MySQL 中布尔是 tinyint(1) |
| 模式匹配 | LIKE / NOT LIKE | username LIKE 'admin%' | % 任意字符,_ 单个字符 |
| 正则 | REGEXP / NOT REGEXP | email REGEXP '^[a-z0-9._%+-]+@' | 性能较差,慎用在大数据量 |
| 逻辑 | AND / OR / NOT | status = 'active' AND age >= 18 | AND 优先级高于 OR,建议加括号 |
二、模糊查询(LIKE)最常见写法
-- 前缀匹配(最常用,索引友好)
WHERE username LIKE 'zhangsan%' -- zhangsan 开头的都匹配
-- 后缀匹配(索引通常失效)
WHERE email LIKE '%@163.com'
-- 任意位置包含(索引基本失效)
WHERE nickname LIKE '%铁锤%'
-- 精确长度匹配(_ 表示一个字符)
WHERE phone LIKE '138________' -- 138 开头的11位手机号
-- 组合模糊 + 条件
WHERE (username LIKE 'admin%' OR nickname LIKE '%admin%')
AND status = 'active'
三、排序(ORDER BY) & 分页(LIMIT)
-- 1. 单字段排序
SELECT * FROM products
ORDER BY price DESC; -- 降序
-- 2. 多字段排序(先按销量降序,销量相同再按价格升序)
SELECT * FROM products
ORDER BY sales DESC, price ASC;
-- 3. 按计算结果排序
SELECT id, username, login_count + 1 AS new_count
FROM users
ORDER BY new_count DESC;
-- 4. 常见分页写法(第 n 页,每页 size 条)
-- 第1页
SELECT * FROM orders
ORDER BY created_at DESC
LIMIT 10;
-- 第3页(每页20条)
SELECT * FROM orders
ORDER BY created_at DESC
LIMIT 20 OFFSET 40; -- 跳过前40条
-- 推荐写法(更清晰)
LIMIT (page-1)*size, size
四、简单聚合函数(无 GROUP BY 时)
| 函数 | 作用 | 示例 | 返回类型 / 注意 |
|---|---|---|---|
| COUNT() | 统计行数 | COUNT(*) / COUNT(id) | COUNT(*) 包含 NULL,COUNT(列) 不含 |
| SUM() | 求和 | SUM(amount) | 只对数值有效 |
| AVG() | 平均值 | AVG(score) | 忽略 NULL |
| MAX() | 最大值 | MAX(created_at) | 日期、字符串、数字都支持 |
| MIN() | 最小值 | MIN(price) | 同上 |
-- 统计活跃用户数
SELECT COUNT(*) AS active_users
FROM users
WHERE status = 'active' AND deleted_at IS NULL;
-- 今日订单总额 & 平均订单金额
SELECT
COUNT(*) AS order_count,
ROUND(SUM(amount), 2) AS total_amount,
ROUND(AVG(amount), 2) AS avg_amount,
MAX(amount) AS max_order,
MIN(amount) AS min_order
FROM orders
WHERE DATE(created_at) = CURDATE();
五、去重(DISTINCT) & 组合查询示例
-- 1. 查询注册过的城市(去重)
SELECT DISTINCT city
FROM users
WHERE city IS NOT NULL
ORDER BY city;
-- 2. 组合条件 + 排序 + 分页 + 限制字段
SELECT id, username, nickname, last_login_time
FROM users
WHERE status = 'active'
AND last_login_time >= DATE_SUB(NOW(), INTERVAL 30 DAY)
AND nickname LIKE '%李%'
ORDER BY last_login_time DESC
LIMIT 15 OFFSET 0;
-- 3. 统计每个状态的用户数量(引入 GROUP BY 预告)
SELECT status, COUNT(*) AS user_count
FROM users
WHERE deleted_at IS NULL
GROUP BY status
ORDER BY user_count DESC;
六、写 SELECT 的高频安全 & 性能建议(2026 年视角)
- 永远不要在生产直接
SELECT *
- 列出明确需要的字段
- 减少 IO、网络传输、内存占用
- WHERE 条件顺序建议(虽然优化器会调整,但可读性重要)
- 先写最能过滤的条件(区分度高的)
- 再写范围 / LIKE
- 最后写 OR / 函数条件
- LIKE 前缀匹配 才能用索引
LIKE 'abc%'→ 好LIKE '%abc'→ 差
- 分页大数据量 推荐“延迟关联”或“游标分页”
-- 传统方式(越往后越慢)
SELECT * FROM logs ORDER BY id DESC LIMIT 1000000,10;
-- 推荐:先找 id 再查详情
SELECT * FROM logs
WHERE id <= (SELECT id FROM logs ORDER BY id DESC LIMIT 1000000,1)
ORDER BY id DESC
LIMIT 10;
- COUNT() vs COUNT(1) vs COUNT(主键)
→ MySQL 优化后几乎无差别,COUNT() 最直观
下一期预告:MySQL 聚合查询 & GROUP BY & HAVING & WITH ROLLUP 详解
有哪种条件组合 / 分页场景你觉得写起来特别烦,或者项目里最常见的 SELECT 模板,欢迎留言,我们一起整理~
祝大家 SELECT 写得精准又高效!🔍
【MySQL 笔记】基本查询(下)—— 表的增删改查 进阶 & 条件 / 排序 / 分页 / 聚合
上一期我们把最基础的 INSERT / UPDATE / DELETE / SELECT 语法过了一遍,今天继续把 SELECT 这个最核心的操作深入展开,重点放在:
- WHERE 条件全家桶
- 模糊查询 & 比较运算
- 排序(ORDER BY)
- 分页(LIMIT / OFFSET)
- 简单聚合(COUNT / SUM / AVG / MAX / MIN)
- 去重(DISTINCT)
- 常用组合写法
这些内容几乎占了日常 SQL 开发的 70% 以上。
一、WHERE 条件常用运算符速查表
| 类别 | 运算符 | 示例 | 说明 / 注意事项 |
|---|---|---|---|
| 比较 | =, !=, <>, >, <, >=, <= | age > 18 | <> 和 != 等价,推荐用 <> |
| 范围 | BETWEEN … AND … | age BETWEEN 18 AND 35 | 包含边界 |
| 集合 | IN / NOT IN | city IN ('北京','上海','广州') | 比多个 OR 效率更高 |
| 空值 | IS NULL / IS NOT NULL | deleted_at IS NULL | 不能用 = NULL |
| 布尔 | IS TRUE / IS FALSE | is_active IS TRUE | MySQL 中布尔是 tinyint(1) |
| 模式匹配 | LIKE / NOT LIKE | username LIKE 'admin%' | % 任意字符,_ 单个字符 |
| 正则 | REGEXP / NOT REGEXP | email REGEXP '^[a-z0-9._%+-]+@' | 性能较差,慎用在大数据量 |
| 逻辑 | AND / OR / NOT | status = 'active' AND age >= 18 | AND 优先级高于 OR,建议加括号 |
二、模糊查询(LIKE)最常见写法
-- 前缀匹配(最常用,索引友好)
WHERE username LIKE 'zhangsan%' -- zhangsan 开头的都匹配
-- 后缀匹配(索引通常失效)
WHERE email LIKE '%@163.com'
-- 任意位置包含(索引基本失效)
WHERE nickname LIKE '%铁锤%'
-- 精确长度匹配(_ 表示一个字符)
WHERE phone LIKE '138________' -- 138 开头的11位手机号
-- 组合模糊 + 条件
WHERE (username LIKE 'admin%' OR nickname LIKE '%admin%')
AND status = 'active'
三、排序(ORDER BY) & 分页(LIMIT)
-- 1. 单字段排序
SELECT * FROM products
ORDER BY price DESC; -- 降序
-- 2. 多字段排序(先按销量降序,销量相同再按价格升序)
SELECT * FROM products
ORDER BY sales DESC, price ASC;
-- 3. 按计算结果排序
SELECT id, username, login_count + 1 AS new_count
FROM users
ORDER BY new_count DESC;
-- 4. 常见分页写法(第 n 页,每页 size 条)
-- 第1页
SELECT * FROM orders
ORDER BY created_at DESC
LIMIT 10;
-- 第3页(每页20条)
SELECT * FROM orders
ORDER BY created_at DESC
LIMIT 20 OFFSET 40; -- 跳过前40条
-- 推荐写法(更清晰)
LIMIT (page-1)*size, size
四、简单聚合函数(无 GROUP BY 时)
| 函数 | 作用 | 示例 | 返回类型 / 注意 |
|---|---|---|---|
| COUNT() | 统计行数 | COUNT(*) / COUNT(id) | COUNT(*) 包含 NULL,COUNT(列) 不含 |
| SUM() | 求和 | SUM(amount) | 只对数值有效 |
| AVG() | 平均值 | AVG(score) | 忽略 NULL |
| MAX() | 最大值 | MAX(created_at) | 日期、字符串、数字都支持 |
| MIN() | 最小值 | MIN(price) | 同上 |
-- 统计活跃用户数
SELECT COUNT(*) AS active_users
FROM users
WHERE status = 'active' AND deleted_at IS NULL;
-- 今日订单总额 & 平均订单金额
SELECT
COUNT(*) AS order_count,
ROUND(SUM(amount), 2) AS total_amount,
ROUND(AVG(amount), 2) AS avg_amount,
MAX(amount) AS max_order,
MIN(amount) AS min_order
FROM orders
WHERE DATE(created_at) = CURDATE();
五、去重(DISTINCT) & 组合查询示例
-- 1. 查询注册过的城市(去重)
SELECT DISTINCT city
FROM users
WHERE city IS NOT NULL
ORDER BY city;
-- 2. 组合条件 + 排序 + 分页 + 限制字段
SELECT id, username, nickname, last_login_time
FROM users
WHERE status = 'active'
AND last_login_time >= DATE_SUB(NOW(), INTERVAL 30 DAY)
AND nickname LIKE '%李%'
ORDER BY last_login_time DESC
LIMIT 15 OFFSET 0;
-- 3. 统计每个状态的用户数量(引入 GROUP BY 预告)
SELECT status, COUNT(*) AS user_count
FROM users
WHERE deleted_at IS NULL
GROUP BY status
ORDER BY user_count DESC;
六、写 SELECT 的高频安全 & 性能建议(2026 年视角)
- 永远不要在生产直接
SELECT *
- 列出明确需要的字段
- 减少 IO、网络传输、内存占用
- WHERE 条件顺序建议(虽然优化器会调整,但可读性重要)
- 先写最能过滤的条件(区分度高的)
- 再写范围 / LIKE
- 最后写 OR / 函数条件
- LIKE 前缀匹配 才能用索引
LIKE 'abc%'→ 好LIKE '%abc'→ 差
- 分页大数据量 推荐“延迟关联”或“游标分页”
-- 传统方式(越往后越慢)
SELECT * FROM logs ORDER BY id DESC LIMIT 1000000,10;
-- 推荐:先找 id 再查详情
SELECT * FROM logs
WHERE id <= (SELECT id FROM logs ORDER BY id DESC LIMIT 1000000,1)
ORDER BY id DESC
LIMIT 10;
- COUNT() vs COUNT(1) vs COUNT(主键)
→ MySQL 优化后几乎无差别,COUNT() 最直观
下一期预告:MySQL 聚合查询 & GROUP BY & HAVING & WITH ROLLUP 详解
有哪种条件组合 / 分页场景你觉得写起来特别烦,或者项目里最常见的 SELECT 模板,欢迎留言,我们一起整理~
祝大家 SELECT 写得精准又高效!🔍