【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见!

相关推荐
一嘴一个橘子2 分钟前
MySqL 的 B+树、 叶子节点、非叶子节点
mysql
麦聪聊数据7 分钟前
企业数据市场建设(三):API 化服务封装,让数据开箱即用、避免重复开发
数据库
麦聪聊数据19 分钟前
企业数据市场建设(四):流程闭环与价值运营,让数据市场真正转起来
运维·数据库
正儿八经的少年26 分钟前
redis 的大 key 和热 key 详解
数据库·redis·缓存
AI砖家30 分钟前
多智能体系统实战:架构设计、数据库表设计与 Skill 体系
数据库·多智能体·skill·agent架构设计·agengt
止语Lab1 小时前
好的 DX 不等于少写代码——三种语言的摩擦力设计课
后端
吃饱了得干活1 小时前
别再手动解析 LLM 输出了!LangChain 四种结构化输出方案对比
后端·python·langchain
程序员天天困1 小时前
Arthas trace 命令怎么用?一行定位最慢那行代码
jvm·后端
Huiturn1 小时前
GPT 5.6 连续编码 10 小时,纯 Python 啃下 Word 二进制格式——doc2docx 实现拆解
后端
夜雪一千1 小时前
MySQL查询条件的顺序是否影响查询效率
数据库·mysql