【MySQL全面教学】MySQL条件查询与排序Day4(2026年)

欢迎来到MySQL系列教程的第4天!今天我们将学习条件查询和排序,这是SQL中最常用的操作。掌握了WHERE、ORDER BY和LIMIT,你就能从海量数据中精准找到需要的信息。让我们开始吧!

文章目录

    • 一、写在前面
    • 二、WHERE子句详解
      • [2.1 比较运算符](#2.1 比较运算符)
      • [2.2 逻辑运算符](#2.2 逻辑运算符)
      • [2.3 IN和NOT IN](#2.3 IN和NOT IN)
      • [2.4 BETWEEN范围查询](#2.4 BETWEEN范围查询)
      • [2.5 LIKE模糊查询](#2.5 LIKE模糊查询)
    • 三、NULL值处理
      • [3.1 IS NULL vs = NULL](#3.1 IS NULL vs = NULL)
      • [3.2 NULL相关函数](#3.2 NULL相关函数)
      • [3.3 NULL值排序](#3.3 NULL值排序)
    • [四、ORDER BY排序](#四、ORDER BY排序)
      • [4.1 单列排序](#4.1 单列排序)
      • [4.2 多列排序](#4.2 多列排序)
      • [4.3 FIELD自定义排序](#4.3 FIELD自定义排序)
      • [4.4 表达式排序](#4.4 表达式排序)
    • 五、LIMIT分页
      • [5.1 基础分页](#5.1 基础分页)
      • [5.2 带排序的分页](#5.2 带排序的分页)
      • [5.3 分页公式](#5.3 分页公式)
    • 六、实战:电商系统的各种查询场景
      • [6.1 用户相关查询](#6.1 用户相关查询)
      • [6.2 商品相关查询](#6.2 商品相关查询)
      • [6.3 订单相关查询](#6.3 订单相关查询)
      • [6.4 综合查询](#6.4 综合查询)
    • 七、踩坑提醒
      • [7.1 LIKE '%xxx%'导致索引失效](#7.1 LIKE '%xxx%'导致索引失效)
      • [7.2 类型转换导致索引失效](#7.2 类型转换导致索引失效)
      • [7.3 OR条件导致索引失效](#7.3 OR条件导致索引失效)
    • 八、面试高频考点
      • 考点1:WHERE和HAVING的区别?
      • [考点2:LIMIT 1000000,10的性能问题?](#考点2:LIMIT 1000000,10的性能问题?)
      • [考点3:如何优化ORDER BY?](#考点3:如何优化ORDER BY?)
      • [考点4:IS NULL和= NULL的区别?](#考点4:IS NULL和= NULL的区别?)
    • 九、总结
    • 十、下一步预告
    • 十一、参考资料
    • 互动话题

一、写在前面

在实际工作中,我们很少直接查询全表数据,而是需要根据各种条件筛选。今天的内容包括:

  • WHERE子句:精确筛选数据
  • NULL值处理:避免常见陷阱
  • ORDER BY排序:让数据有序呈现
  • LIMIT分页:大数据量的分页显示

二、WHERE子句详解

WHERE子句用于筛选满足条件的记录,是SELECT语句中最常用的子句。

2.1 比较运算符

sql 复制代码
-- 等于 =
SELECT * FROM users WHERE status = 1;

-- 不等于 != 或 <>
SELECT * FROM users WHERE status != 0;
SELECT * FROM users WHERE status <> 0;

-- 大于、小于
SELECT * FROM products WHERE price > 5000;
SELECT * FROM products WHERE stock < 10;

-- 大于等于、小于等于
SELECT * FROM orders WHERE total_amount >= 10000;
SELECT * FROM products WHERE price <= 1000;

-- 范围查询(等同于 >= AND <=)
SELECT * FROM products WHERE price BETWEEN 1000 AND 5000;

2.2 逻辑运算符

sql 复制代码
-- AND:同时满足多个条件
SELECT * FROM products 
WHERE price > 1000 AND stock > 0 AND status = 1;

-- OR:满足任一条件
SELECT * FROM products 
WHERE category = '手机' OR category = '电脑';

-- NOT:取反
SELECT * FROM users WHERE NOT status = 0;

-- 混合使用(注意优先级:NOT > AND > OR)
SELECT * FROM products 
WHERE (category = '手机' OR category = '电脑') 
  AND price < 10000 
  AND status = 1;

2.3 IN和NOT IN

sql 复制代码
-- IN:在指定集合中
SELECT * FROM products WHERE category IN ('手机', '电脑', '平板');
-- 等同于:
SELECT * FROM products 
WHERE category = '手机' OR category = '电脑' OR category = '平板';

-- NOT IN:不在指定集合中
SELECT * FROM orders WHERE status NOT IN (3, 4);
-- 查询未完成的订单(排除已完成和已取消)

-- 子查询配合IN
SELECT * FROM users 
WHERE id IN (SELECT user_id FROM orders WHERE total_amount > 10000);

2.4 BETWEEN范围查询

sql 复制代码
-- 数值范围
SELECT * FROM products WHERE price BETWEEN 1000 AND 5000;

-- 日期范围
SELECT * FROM orders 
WHERE created_at BETWEEN '2024-01-01' AND '2024-01-31';
-- 注意:BETWEEN包含边界值

-- 等同于:
SELECT * FROM orders 
WHERE created_at >= '2024-01-01' AND created_at <= '2024-01-31';

-- NOT BETWEEN
SELECT * FROM products WHERE price NOT BETWEEN 100 AND 1000;

2.5 LIKE模糊查询

sql 复制代码
-- % 匹配任意多个字符
SELECT * FROM products WHERE name LIKE '%iPhone%';  -- 包含iPhone
SELECT * FROM users WHERE username LIKE 'zhang%';   -- 以zhang开头
SELECT * FROM users WHERE email LIKE '%@gmail.com'; -- 以@gmail.com结尾

-- _ 匹配单个字符
SELECT * FROM products WHERE name LIKE 'iPhone _';  -- iPhone + 一个字符
SELECT * FROM users WHERE username LIKE 'user00_';  -- user001, user002等

-- 转义特殊字符
SELECT * FROM products WHERE name LIKE '%\%%';  -- 包含%符号
SELECT * FROM products WHERE name LIKE '%\_%';  -- 包含_符号

三、NULL值处理

3.1 IS NULL vs = NULL

这是MySQL中最常见的错误之一!

sql 复制代码
-- 错误!= NULL 永远返回空结果
SELECT * FROM users WHERE phone = NULL;  -- 错误!

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

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

原因: NULL表示"未知",任何与NULL的比较结果都是NULL(假),必须使用IS NULL或IS NOT NULL。

3.2 NULL相关函数

sql 复制代码
-- IFNULL:如果为NULL则返回默认值
SELECT 
    username,
    IFNULL(phone, '未绑定') AS phone_display
FROM users;

-- COALESCE:返回第一个非NULL值
SELECT 
    username,
    COALESCE(phone, email, '无联系方式') AS contact
FROM users;

-- NULLIF:如果相等则返回NULL
SELECT NULLIF(1, 1);  -- 返回NULL
SELECT NULLIF(1, 2);  -- 返回1

3.3 NULL值排序

sql 复制代码
-- MySQL中NULL默认排在最前面(升序)
SELECT * FROM users ORDER BY phone;  -- NULL在前

-- 让NULL排在最后
SELECT * FROM users ORDER BY phone IS NULL, phone;

-- 或者使用IFNULL转换
SELECT * FROM users ORDER BY IFNULL(phone, 'ZZZZZ');

四、ORDER BY排序

4.1 单列排序

sql 复制代码
-- 升序(默认)
SELECT * FROM products ORDER BY price;
SELECT * FROM products ORDER BY price ASC;

-- 降序
SELECT * FROM products ORDER BY price DESC;

-- 按日期排序
SELECT * FROM orders ORDER BY created_at DESC;  -- 最新的在前

4.2 多列排序

sql 复制代码
-- 先按状态排序,再按价格排序
SELECT * FROM products 
ORDER BY status DESC, price ASC;

-- 先按分类排序,再按价格降序,最后按ID升序
SELECT * FROM products 
ORDER BY category, price DESC, id;

4.3 FIELD自定义排序

有时我们需要按照自定义的顺序排序:

sql 复制代码
-- 按状态自定义顺序:已支付(1) > 待支付(0) > 已发货(2) > 已完成(3) > 已取消(4)
SELECT * FROM orders 
ORDER BY FIELD(status, 1, 0, 2, 3, 4);

-- 按指定ID顺序排序
SELECT * FROM products 
WHERE id IN (3, 1, 2)
ORDER BY FIELD(id, 3, 1, 2);  -- 结果按3,1,2的顺序

4.4 表达式排序

sql 复制代码
-- 按价格区间排序(先显示便宜的)
SELECT *, 
    CASE 
        WHEN price < 1000 THEN 1
        WHEN price < 5000 THEN 2
        ELSE 3
    END AS price_level
FROM products
ORDER BY price_level, price;

五、LIMIT分页

5.1 基础分页

sql 复制代码
-- 只返回前10条
SELECT * FROM products LIMIT 10;

-- 返回第11-20条(第2页,每页10条)
SELECT * FROM products LIMIT 10 OFFSET 10;
-- 或简写:
SELECT * FROM products LIMIT 10, 10;  -- 从第10条开始,取10条

5.2 带排序的分页

sql 复制代码
-- 按价格排序后分页
SELECT * FROM products 
ORDER BY price ASC 
LIMIT 20 OFFSET 40;  -- 第3页,每页20条

-- 按创建时间倒序分页(最新数据在前)
SELECT * FROM orders 
ORDER BY created_at DESC 
LIMIT 10 OFFSET 0;  -- 第1页

5.3 分页公式

sql 复制代码
-- 通用分页公式
-- 第page页,每页pageSize条
-- OFFSET = (page - 1) * pageSize

-- 第5页,每页20条
SET @page = 5;
SET @pageSize = 20;
SET @offset = (@page - 1) * @pageSize;

SELECT * FROM products 
ORDER BY id 
LIMIT @pageSize OFFSET @offset;

六、实战:电商系统的各种查询场景

6.1 用户相关查询

sql 复制代码
-- 查询已绑定手机号的活跃用户
SELECT id, username, phone, email 
FROM users 
WHERE status = 1 
  AND phone IS NOT NULL 
ORDER BY created_at DESC 
LIMIT 20;

-- 查询用户名包含zhang的用户
SELECT * FROM users WHERE username LIKE '%zhang%';

-- 查询注册时间在2024年1月的用户
SELECT * FROM users 
WHERE created_at >= '2024-01-01' 
  AND created_at < '2024-02-01';

6.2 商品相关查询

sql 复制代码
-- 查询上架且库存充足的商品,按价格排序
SELECT id, name, price, stock 
FROM products 
WHERE status = 1 AND stock > 0 
ORDER BY price ASC 
LIMIT 10;

-- 查询价格在1000-5000之间的手机或电脑
SELECT * FROM products 
WHERE price BETWEEN 1000 AND 5000 
  AND category IN ('手机', '电脑')
ORDER BY price DESC;

-- 查询库存不足的商品(需要补货)
SELECT * FROM products WHERE stock < 10 ORDER BY stock ASC;

6.3 订单相关查询

sql 复制代码
-- 查询最近7天的订单
SELECT * FROM orders 
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
ORDER BY created_at DESC;

-- 查询金额大于10000的已支付订单
SELECT * FROM orders 
WHERE total_amount > 10000 AND status = 1
ORDER BY total_amount DESC;

-- 查询特定用户的所有订单
SELECT * FROM orders 
WHERE user_id = 1 
ORDER BY created_at DESC 
LIMIT 10;

-- 查询待支付或已支付的订单(按状态优先级排序)
SELECT * FROM orders 
WHERE status IN (0, 1)
ORDER BY FIELD(status, 1, 0), created_at DESC;

6.4 综合查询

sql 复制代码
-- 查询高价值用户的订单(订单金额大于平均值的订单)
SELECT o.*, u.username 
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.total_amount > (SELECT AVG(total_amount) FROM orders)
ORDER BY o.total_amount DESC
LIMIT 10;

-- 查询每个用户的最新订单
SELECT o1.*
FROM orders o1
WHERE o1.created_at = (
    SELECT MAX(created_at) 
    FROM orders o2 
    WHERE o2.user_id = o1.user_id
)
ORDER BY o1.user_id;

七、踩坑提醒

7.1 LIKE '%xxx%'导致索引失效

sql 复制代码
-- 有索引的查询(使用索引)
SELECT * FROM users WHERE username = 'zhangsan';  -- 用索引
SELECT * FROM users WHERE username LIKE 'zhang%';  -- 用索引(前缀匹配)

-- 索引失效的查询(全表扫描)
SELECT * FROM users WHERE username LIKE '%zhang';  -- 全表扫描
SELECT * FROM users WHERE username LIKE '%zhang%';  -- 全表扫描

解决方案:

  1. 避免使用 %xxx% 模糊查询
  2. 使用全文索引(FULLTEXT)
  3. 使用搜索引擎(Elasticsearch)
  4. 使用反向索引或分词技术

7.2 类型转换导致索引失效

sql 复制代码
-- 表结构:phone CHAR(11)
-- 错误:类型转换导致索引失效
SELECT * FROM users WHERE phone = 13800138001;  -- 数字,会转换

-- 正确:使用字符串
SELECT * FROM users WHERE phone = '13800138001';  -- 字符串,用索引

7.3 OR条件导致索引失效

sql 复制代码
-- 可能不走索引(取决于优化器)
SELECT * FROM products WHERE category = '手机' OR price < 1000;

-- 优化方案1:使用UNION
SELECT * FROM products WHERE category = '手机'
UNION ALL
SELECT * FROM products WHERE price < 1000;

-- 优化方案2:使用IN(如果条件适合)
SELECT * FROM products WHERE category IN ('手机', '电脑');

八、面试高频考点

考点1:WHERE和HAVING的区别?

答案:

特性 WHERE HAVING
执行时机 分组前过滤 分组后过滤
作用对象 原始数据行 分组后的结果
可用条件 原始列、表达式 聚合函数、别名
性能 更好(先过滤) 稍差(后过滤)
sql 复制代码
-- WHERE:过滤原始行
SELECT category, AVG(price) AS avg_price
FROM products
WHERE status = 1  -- 先过滤上架商品
GROUP BY category;

-- HAVING:过滤分组结果
SELECT category, AVG(price) AS avg_price
FROM products
GROUP BY category
HAVING AVG(price) > 5000;  -- 过滤平均价格大于5000的分类

考点2:LIMIT 1000000,10的性能问题?

答案: 深度分页性能很差,因为MySQL需要先扫描1000010行,再返回最后10行。

解决方案:

sql 复制代码
-- 低效:深度分页
SELECT * FROM orders LIMIT 1000000, 10;

-- 优化方案1:使用覆盖索引
SELECT * FROM orders o
JOIN (SELECT id FROM orders LIMIT 1000000, 10) tmp ON o.id = tmp.id;

-- 优化方案2:使用范围查询(推荐)
SELECT * FROM orders 
WHERE id > 1000000 
ORDER BY id 
LIMIT 10;

-- 优化方案3:记录上次位置
SELECT * FROM orders 
WHERE created_at < '上次最后一条的时间'
ORDER BY created_at DESC 
LIMIT 10;

考点3:如何优化ORDER BY?

答案:

  1. 使用索引覆盖排序字段
  2. 避免使用SELECT *,只查询需要的列
  3. 减少排序的数据量(先用WHERE过滤)
  4. 考虑使用内存排序(sort_buffer_size)
sql 复制代码
-- 有索引的排序(filesort在内存中完成)
SELECT id, name, price FROM products ORDER BY price;

-- 优化:添加复合索引
ALTER TABLE products ADD INDEX idx_status_price (status, price);

-- 查询时使用索引覆盖
SELECT id, name, price FROM products 
WHERE status = 1 ORDER BY price;  -- 使用索引排序

考点4:IS NULL和= NULL的区别?

答案:

  • IS NULL 是标准SQL语法,用于判断是否为NULL
  • = NULL 是错误的写法,任何值与NULL比较都返回NULL(假)
  • 必须使用 IS NULLIS NOT NULL 判断NULL值

九、总结

今天我们学习了:

  1. WHERE子句:比较运算符、逻辑运算符、IN、BETWEEN、LIKE
  2. NULL处理:IS NULL、IFNULL、COALESCE
  3. ORDER BY排序:单列、多列、FIELD自定义排序
  4. LIMIT分页:基础分页、深度分页优化
  5. 实战:电商系统的各种查询场景

核心要点:

  • LIKE '%xxx%'会导致索引失效
  • 必须用IS NULL判断NULL值
  • 深度分页需要优化
  • WHERE和HAVING的使用场景不同

十、下一步预告

Day5:MySQL聚合函数与分组

我们将学习:

  • COUNT/SUM/AVG/MAX/MIN聚合函数
  • GROUP BY分组统计
  • HAVING过滤分组
  • 复杂统计查询实战

十一、参考资料

  1. MySQL 8.0官方文档 - SELECT语句
  2. 高性能MySQL(第4版)- 查询性能优化

互动话题

  1. 你在工作中遇到过哪些慢查询问题?是怎么优化的?
  2. 你们项目中的分页是怎么实现的?有没有遇到深度分页的性能问题?
  3. 对于LIKE模糊查询,你们有什么好的解决方案?

如果觉得有帮助,请点赞+收藏+关注!我们Day5见!

相关推荐
丷丩6 小时前
Postgresql基础实践教程(四)
数据库·postgresql
六月雨滴6 小时前
RMAN 增量备份(Incremental Backup)
数据库·oracle
2401_878820476 小时前
Redis+Lua脚本实现全局令牌桶限流
数据库·redis·lua
她的男孩6 小时前
后台权限不只是菜单隐藏:Forge Admin 的 RBAC 权限链路拆解
java·后端·架构
Slow菜鸟7 小时前
Maven 仓库下载机制
java·数据库·maven
苏三说技术7 小时前
IntelliJ IDEA 从卡顿到起飞,只用改这些。。。
后端
身如柳絮随风扬7 小时前
Redis 主从复制与哨兵机制详解:从原理到高可用实战
数据库·redis·缓存
冰小忆7 小时前
类变量在继承场景下的初始化规则是怎样的?
java·前端·数据库
YL200404267 小时前
MySQL-运维篇-主从复制
运维·数据库·mysql