SQL查询从入门到精通:排序、聚合、分组、分页与多表关联全攻略

SQL查询从入门到精通:排序、聚合、分组、分页与多表关联全攻略 一文搞懂DQL核心查询语法从单表操作到多表关联全覆盖前言很多初学者在写SQL时都会遇到这样的困惑明明数据就在表里但就是查不出来想要的结果。排序乱了、统计错了、分组懵了、多表关联更是直接放弃……其实SQL查询是有固定套路的。只要掌握了排序、聚合、分组、分页这四大金刚再理解了多表关联的核心逻辑80%的查询需求都能轻松搞定。本文基于真实教学笔记整理手把手带你掌握DQL查询语言的核心知识点包含大量可直接运行的实战案例。建议收藏遇到问题随时查阅一、排序查询ORDER BY1.1 基本语法排序是查询中最常用的操作之一通过ORDER BY关键字实现sqlSELECT * FROM 表名 ORDER BY 列名 [ASC | DESC]; -- ASC升序默认从小到大 -- DESC降序从大到小1.2 单列排序sql-- 查询所有商品按评分从高到低排序 SELECT * FROM products ORDER BY score DESC; -- 查询所有商品按价格从低到高排序 SELECT * FROM products ORDER BY price ASC;1.3 多列排序当第一列的值相同时再按第二列排序sql-- 先按价格降序价格相同的再按分类降序 SELECT * FROM products ORDER BY price DESC, category_id DESC;1.4 去重后排序sql-- 查询所有不重复的价格并按降序排列 SELECT DISTINCT price FROM products ORDER BY price DESC;1.5 排序的注意事项要点说明排序时机在SELECT语句执行之后、返回结果之前进行NULL值处理默认NULL值最小升序排最前降序排最后多列排序先排第一列相同再排第二列二、聚合查询聚合函数2.1 什么是聚合函数聚合函数又叫组函数或统计函数用来对表中的指定列数据进行统计计算。聚合函数作用注意事项COUNT()统计记录数忽略NULL值SUM()求和非数值列结果为0AVG()求平均值忽略NULL值MAX()求最大值字符串按字典序MIN()求最小值字符串按字典序2.2 基本用法sql-- 统计商品总数量 SELECT COUNT(id) AS cnt FROM products; SELECT COUNT(*) AS cnt FROM products; -- 包含NULL行 -- 查询价格大于2000的商品数量 SELECT COUNT(*) AS cnt FROM products WHERE price 2000; -- 查询自营商品的总价 SELECT SUM(price) AS total FROM products WHERE is_self 自营; -- 查询非自营商品的平均价格 SELECT AVG(price) AS avg_price FROM products WHERE is_self 非自营; -- 查询最高价和最低价 SELECT MAX(price) AS max_price, MIN(price) AS min_price FROM products;2.3 COUNT(*) 与 COUNT(列) 的区别写法统计范围是否忽略NULLCOUNT(*)所有行不忽略COUNT(列名)该列非NULL的行忽略NULLsql-- 如果id列有NULL值两者结果可能不同 SELECT COUNT(*) AS 全部行 FROM products; -- 包含NULL SELECT COUNT(id) AS 非空行 FROM products; -- 不含NULL三、分组查询GROUP BY3.1 核心思想先分组后聚合——把数据按指定列的值划分到不同组再对每个组进行统计计算。https://cdn.nlark.com/yuque/0/2026/png/22228747/1781014858173-93f61c1c-4817-42c7-88a6-aafb971e0c3e.png3.2 基本语法sqlSELECT 分组字段, 聚合函数(列) FROM 表名 GROUP BY 分组字段;3.3 单字段分组sql-- 统计各个分类的商品数量 SELECT category_id, COUNT(*) AS cnt FROM products GROUP BY category_id; -- 统计自营和非自营的总价 SELECT is_self, SUM(price) AS total FROM products GROUP BY is_self;3.4 分组前的数据过滤WHERE GROUP BYsql-- 统计有评分的分类中有多少个商品 SELECT category_id, COUNT(*) AS cnt FROM products WHERE score IS NOT NULL GROUP BY category_id; -- 统计自营和非自营的平均评分 SELECT is_self, AVG(score) AS avg_score FROM products GROUP BY is_self;3.5 多字段分组sql-- 先按分类分组再按是否自营分组统计每组数量 SELECT category_id, is_self, COUNT(*) AS cnt FROM products GROUP BY category_id, is_self; -- 统计每个分类中自营/非自营的平均价格 SELECT category_id, is_self, AVG(price) AS avg_price FROM products GROUP BY category_id, is_self;⚠️ 分组查询的重要规则SELECT 后面只能出现两类内容分组字段写在 GROUP BY 后面的列聚合函数COUNT、SUM、AVG等如果 SELECT 中出现了既不是分组字段也不是聚合函数的列MySQL会报错。四、分组过滤HAVING4.1 WHERE vs HAVING对比WHEREHAVING过滤时机分组之前分组之后能否使用聚合函数❌ 不能✅ 可以别名支持❌ 不支持✅ 支持过滤对象原始行分组后的组4.2 基本语法sqlSELECT 分组字段, 聚合函数(列) FROM 表名 GROUP BY 分组字段 HAVING 聚合函数条件;4.3 实战案例sql-- 统计每个分类的平均价格筛选出平均价格 3000 的分类 SELECT category_id, AVG(price) AS avg_price FROM products GROUP BY category_id HAVING avg_price 3000; -- 统计有评分的分类的平均价格筛选出平均价格 1000 的分类 SELECT category_id, AVG(price) AS avg_price FROM products WHERE score IS NOT NULL GROUP BY category_id HAVING avg_price 1000; -- 统计每个分类的平均评分筛选出平均评分 9.5 的分类 SELECT category_id, AVG(score) AS avg_score FROM products GROUP BY category_id HAVING avg_score 9.5;五、分页查询LIMIT5.1 为什么需要分页在实际项目中一张表可能有成千上万条数据。如果一次性全部展示前端渲染会很慢用户体验也会很差。这就是为什么网页都会有分页导航。5.2 基本语法sqlSELECT 字段列表 FROM 表名 LIMIT m, n; -- m偏移量从第 m1 行开始取从 0 开始计数 -- n要取的行数每页显示多少条5.3 实战案例sql-- 获取价格降序后的前3条 SELECT * FROM products ORDER BY price DESC LIMIT 0, 3; -- 等价于 SELECT * FROM products ORDER BY price DESC LIMIT 3; -- 商品按价格从高到低排序获取第2页数据每页3条 -- 第1页LIMIT 0, 3 -- 第2页LIMIT 3, 3 -- 第3页LIMIT 6, 3 SELECT * FROM products ORDER BY price DESC LIMIT 3, 3;5.4 分页公式text第 page 页每页 size 条数据 LIMIT (page - 1) * size, size page1, size10 → LIMIT 0, 10 page2, size10 → LIMIT 10, 10 page3, size10 → LIMIT 20, 10 注意事项如果LIMIT的偏移量超出了数据总行数不会报错只会返回空结果LIMIT通常放在SQL语句的最后执行六、SQL执行顺序核心很多初学者写的SQL报错就是因为不知道SQL的执行顺序。SQL的书写顺序和执行顺序是不同的书写顺序sqlSELECT [DISTINCT] 分组字段, 聚合函数 FROM 表名 WHERE 条件 GROUP BY 分组字段 HAVING 条件 ORDER BY 字段 LIMIT m, n;实际执行顺序text1️⃣ FROM → 确定数据来源 2️⃣ JOIN → 关联其他表 3️⃣ ON → 连接条件 4️⃣ WHERE → 行级过滤 5️⃣ GROUP BY → 分组 6️⃣ 聚合函数 → 计算统计值 7️⃣ HAVING → 组级过滤 8️⃣ SELECT → 选择列 9️⃣ DISTINCT → 去重 ORDER BY → 排序 1️⃣1️⃣ LIMIT → 分页截取 理解执行顺序的意义WHERE 中不能用聚合函数→ 因为聚合函数在第⑥步才执行而 WHERE 在第④步执行HAVING 中可以用聚合函数→ 因为 HAVING 在第⑦步执行聚合函数已经算完了ORDER BY 中可以用别名→ 因为 SELECT 在第⑧步执行ORDER BY 在第⑩步执行LIMIT 必须放最后→ 因为它是最后一步执行的七、表关系与外键7.1 三种表关系关系类型描述举例一对多A表一行 → B表多行一个分类 → 多个商品多对多A表一行 → B表多行反之亦然学生 ↔ 课程需要中间表一对一A表一行 → B表一行员工基础信息 ↔ 员工详情7.2 外键与外键约束外键从表中引用主表主键的列。sql-- 主表分类表 CREATE TABLE category ( id INT PRIMARY KEY, name VARCHAR(20) ); -- 从表商品表category_id 指向 category.id CREATE TABLE products ( id INT PRIMARY KEY, name VARCHAR(20), category_id INT, FOREIGN KEY (category_id) REFERENCES category(id) -- 外键约束 );外键约束的作用✅ 保证插入数据的准确性从表的外键值必须在主表中存在✅ 保证删除数据的完整性被引用的主表记录不能被删除实际开发建议⚠️实际开发中很少使用物理外键约束通常从代码层面维护表关系。因为外键约束会降低增删改的性能增加开发复杂度。八、多表关联查询JOIN8.1 核心思想JOIN 的核心意义是把多张表中的数据按某种规则拼成一张大表。真实业务中数据分散存储在多张表里查询时需要把它们关联起来看。8.2 笛卡尔积交叉连接概念左表的每一行和右表的每一行无条件配对。sql-- 两种写法等价 SELECT * FROM 表1, 表2; SELECT * FROM 表1 JOIN 表2;⚠️ 笛卡尔积会产生大量垃圾数据实际使用中几乎必须配合 ON 或 WHERE 条件过滤。8.3 内连接INNER JOIN返回两张表都满足连接条件的部分交集。sqlSELECT * FROM category c INNER JOIN products p ON c.id p.category_id; -- 简写 SELECT * FROM category c JOIN products p ON c.id p.category_id;https://cdn.nlark.com/yuque/0/2026/png/22228747/1781078114595-c6081ff5-3052-4e0f-8f24-b85d7039b789.png8.4 左外连接LEFT JOIN左表全部 右表匹配部分。右表无匹配时填充 NULL。sqlSELECT * FROM category c LEFT JOIN products p ON c.id p.category_id;https://cdn.nlark.com/yuque/0/2026/png/22228747/1781078196121-0cf991a1-ec55-446c-aaaa-8b9e727f0d1c.png8.5 右外连接RIGHT JOIN右表全部 左表匹配部分。左表无匹配时填充 NULL。sqlSELECT * FROM category c RIGHT JOIN products p ON c.id p.category_id;8.6 全外连接FULL JOIN左表全部 交集 右表全部。MySQL 不支持FULL JOIN用UNION模拟sql-- UNION去重合并 SELECT * FROM products p LEFT JOIN category c ON p.category_id c.id UNION SELECT * FROM products p RIGHT JOIN category c ON p.category_id c.id; -- UNION ALL不去重合并 SELECT * FROM products p LEFT JOIN category c ON p.category_id c.id UNION ALL SELECT * FROM products p RIGHT JOIN category c ON p.category_id c.id;九、知识速查表查询关键字一览关键字作用执行时机能否用聚合函数WHERE行级过滤分组前❌ 不能GROUP BY分组聚合前❌ 不能只写分组字段HAVING组级过滤分组后✅ 可以ORDER BY排序查询后❌ 不能LIMIT分页最后❌ 不能JOIN 类型对比JOIN 类型结果图示INNER JOIN两表匹配的交集中间交集LEFT JOIN左表全部 右表匹配左圆全 交集RIGHT JOIN右表全部 左表匹配右圆全 交集FULL JOIN两表全部两圆全MySQL用UNION模拟十、总结本文系统讲解了DQL查询语言的五大核心模块排序查询ORDER BY→ 让结果按指定顺序展示聚合查询聚合函数→ 对数据进行统计计算分组查询GROUP BY→ 先分组、后聚合实现分类统计分组过滤HAVING→ 对分组后的结果进行二次筛选分页查询LIMIT→ 控制返回的行数范围同时深入讲解了✅SQL执行顺序理解它90%的报错都能自己解决✅表关系与外键一对多、多对多、一对一✅多表关联查询INNER JOIN、LEFT JOIN、RIGHT JOIN一句话建议先单表练扎实再攻克多表关联。排序、聚合、分组、分页是DQL的四大基石务必熟练掌握如果这篇文章对你有帮助欢迎点赞 收藏⭐ 转发你的支持是我持续创作的动力有疑问欢迎在评论区留言我会第一时间回复