--- title: "12-排序与语句执行顺序" created: 2025-11-25 tags: - 项目筑基 --- # 排序与语句执行顺序 ### 对查询的结果进行排序 #### ORDER子句 ```sql SELECT 列名1,列名2…… FROM 表名 ORDER BY 列名n ``` ##### 默认升序(asc) 查询教师的姓名和职称 职称按拼音先后顺序排序 ```sql SELECT 姓名,职称 FROM 教师 ORDER BY 职称 SELECT 姓名,职称 FROM 教师 ORDER BY 职称 asc ``` ##### 自定义排序 跟Excel里差不多 给出自己想要的顺序就行了 查询教师的姓名和职称 职称按职称高低顺序排序 CASE……END WHEN……THEN ```sql SELECT 姓名,职称 FROM 教师 ORDER BY CASE WHEN 职称='教授' THEN 1 WHEN 职称='副教授' THEN 2 WHEN 职称='讲师' THEN 3 WHEN 职称='助教' THEN 4 ELSE 5 END ``` ##### 降序(desc) 排序选课成绩 从高到低 DESC ```sql SELECT 学号,课程编号,成绩 FROM 选课成绩 ORDER BY 成绩 DESC ``` 可见在ORDER BY 中 就没有跟GROUP BY那样的要求对应显示 ##### 升降混合 对多个字段排序 查询员工名字和工资 按工资升序排 如果工作一样 再按名字降序排 ```sql Select ename,sal from emp order by sal asc,ename desc ``` sal在前 起主导 只有sal相等的时候才会考虑启用ename排序 ##### 按字段位置排序 ```sql Select ename,sal from emp order by 2 //2表示第2列 ``` 不健壮(列的顺序很容易发生改变) 不建议使用 #### TOP子句 SELECT TOP(N)【 PERCENT】列名(,列名……) FROM 表名 top(n) 前n个 top(n)percent 前百分之n WITH TIES ###### 前N个 找出前五名 ```sql SELECT TOP(5) 学号,课程编号,成绩 FROM 选课成绩 ORDER BY 成绩 DESC --还有很多相同成绩的 应该也入围 WITH TIES SELECT TOP(5) WITH TIES 学号,课程编号,成绩 FROM 选课成绩 ORDER BY 成绩 DESC ``` ###### 前百分之N ```sql --PERCENT 百分比 --查询前30%的成绩信息 SELECT TOP(30) PERCENT 学号,课程编号,成绩 FROM 选课成绩 ORDER BY 成绩 DESC --同理 还有相同的 SELECT TOP(30) PERCENT WITH TIES 学号,课程编号,成绩 FROM 选课成绩 ORDER BY 成绩 DESC ``` ##### --先排序才会有TOP ```sql SELECT 学号,课程编号,成绩 FROM 选课成绩 SELECT TOP(30) PERCENT 学号,课程编号,成绩 FROM 选课成绩 ``` 只是选出了在表上端的前30% 而不是真正的排名前30% ```sql SELECT TOP(30) PERCENT 学号,课程编号,成绩 FROM 选课成绩 ORDER BY 成绩 DESC ``` 真正要达到效果得先排序 同时也可以发现 语句是先进行排序再进行TOP函数的 mysql中无top用法 ### \*分析语句执行顺序 理解了这些语句的查询顺序 才能对这个查询代码的编写更加清晰 所得的代码执行起来效率也会更高 是一个锦上添花的作用 首先 书写顺序应该是 Select……from……where……group by……having……order by…… 这点熟悉了就知道 但是 在这里面其实有很多讲究 这一个个关键词是有执行顺序的 1、From 2、Where 3、Group by 4、Having 5、Select 6、Order by 简单理解就是: 从某张表中查询数据 先经过where条件筛选出有价值的数据 对这些有价值的数据进行分组 分组之后可以使用having继续筛选 Select把结果显示出来 最后排序输出 先分析第一个 from是最先执行的 这个显而易见 比如这样 `select * from books` 简单的一句查询 它的意思就是 从books里面找到所有数据 先from 再 select ```sql select * from books where publisher='人民出版社' ``` 在找到的这些数据里面 挑选符合条件的显示出来 from where select 1、2能不能颠倒? ```sql select name from (select * from books where publisher='人民出版社') ``` 这段语句是错的 它想表达的含义呢可能是 从找到的人民出版社的字段表中 找书名 那么是不是 from →where→select→from→select 错误的原因可能就在这 外层的from都还没执行 怎么可能执行了where和select操作 这个例子可能不太标准 也只是转个牛角尖去看1、2的顺序 其实1、2间没什么疑问 (这个问题只要加上别名就能解决 见后方子查询和别名的妙用) 3 group by一加入呢 疑问就多起来了 困扰我很久的几个问题也就在这一部分 比如 我找到出版社里 最贵的那本书的价钱 那我该怎么去知道这个最高的书是什么呢? 它不让我放进去啊! ![[image-fee1ceb6.png]] 为什么使用了分组 select后面的字段就只能是分组的字段和聚合函数 为什么聚合函数就能放进去 用执行顺序来分析一下 (from where groupby having select orderby) 先from 从books表里面取数据(此时数据未经筛选 就是一整个表) Where没有 Group by 把这些数据按出版社进行分组 (此时数据变成了N条[跟出版社的数量有关]) 重点!数据只有N条了 比如有3个出版社 现在等待被select的表里面的数据只有3条 但是!Name不止3个 假设books表中一共有10个名字 那我这10个名字怎么去跟预选的3个条数去对应?前三个名字分别对于这3个出版社?显然不合理 就算不报错也没有意义 意思就是name并没有参与分组 分组的只有publisher 他们的条目数量不匹配 因此无意义 那么为什么聚合函数就能放select后面 涉及到另外一个知识 就是聚合函数又叫做分组函数 它本是和分组相生的 那可能会有疑惑 我 `select avg(price) from books` 就可以执行啊 它又没group by分组 不不不 它是已经分了组的 不信可以试试这句 `select avg(price),name from books` 它又报错说name没有在聚合函数或者group by子句中 知识点来了 当聚合函数出现 又没有明确的group by子句时 它是默认把整个表分为一个组的 相当于group by 列1,列2…列n (所有列都放进去) 所以 聚合函数avg是参与了分组的 它的意思就是对这些已经分了组的数据 去求平均数 比如共3个出版社 出版社1有4本书 出版社2有3本书 出版社3有2本书 分完组是三条记录 第一条记录的第1列是出版社1 第2列就是4本书价钱加起来除以4 第二条记录……第三条…… 他们的条目都是3 就没有什么不匹配、冲突的问题了 那么这个问题应该解决了 还有一个问题 ![[image-205576d2.png]] Where子句里面为什么不能有聚合函数? 同样搬过来(from where group by having select order by) 分组是在where之后才会执行的 就是说 我先对一个数据进行筛选 对于这个已经where过的数据才去分组 这就涉及到它与having的区别 后面再分析 这个 `select name from books where price>avg(price)` avg在where里面 可是where先执行 还没轮到分组呢 跟前面from where select 其实是一个道理 只是前面的那个更符合我们的认知 觉得不太可能 这个稍微隐晦些 就是一样的 当真正记住了、理解了这个执行过程 就会发现其实这个错误也很离谱 到了having 对于having 错误可能没太多因为跟正常人想法是差不多的 但是涉及到效率问题 顾名思义吗 having有 它执行顺序在group by后面 写法也是在group by后面(可能这也是不容易犯错的一个原因) 意味着 我要对分好组的这些数据 去做一个having 这些数据里“有”…… 所以理解了 where在group by前 having在group by后吗 一个分组先筛选 一个分组后筛选 可能会疑惑 分组前筛选和分组后筛选有啥区别 不都一样 给出一个例子 要想查询 每个部门的最高薪资 要求显示最高薪资大于3000的 那么两种思路 光看题目跟着题目做的话 得到这样的语句 ```sql select deptno,max(sal) from emp group by deptno having max(sal)>3000 ``` 先分组 分组完之后 在每个组里分别找max 再去having筛选 最后才得到结果 ![[image-8fd97bf7.png]] 不仅步骤多 数据量也大 那么另一种 ```sql select deptno,max(sal) from emp where sal>3000 group by deptno ``` 先筛选出大于3000的 不满足的直接滚蛋 再对剩余的一部分数据分组 在里面去找max ![[image-bc9b10d1.png]] 这样一来 要处理的数据量就小了很多 步骤也变少了很多 这就是效率上面的区别 所以 where和having优先选择where where实在完成不了了 才用having 什么情况where实在完成不了? 比如 要对使用聚合函数之后的数据再进行操作的查询 查平均薪资大于2500的 `select deptno,avg(sal) from emp group by deptno having avg(sal)>2500` 还有要注意的一个 having不能单独存在 一定要和group by联合使用 ![[image-ba84b0b2.png]] Order by就查询完了 按一个顺序排序显示嘛 容易理解 关于这六条语句的执行顺序 存在的一些问题就都可以理解了 来个大杂烩 找出每个岗位的平均薪资 要求显示平均薪资大于1500的 除MANAGER岗位之外 要求按照平均薪资 按降序排 ```sql SELECT Job,avg(sal) as avgsal FROM emp WHERE job!='MANAGER' GROUP BY job HAVING avg(sal)>1500 ORDER BY avgsal desc; ``` 还有一种关于使用别名来验证这些执行顺序的方法 看到过 但当时没太注意 找不到了 那个确实巧妙 这样也能理解 对于这个已经没啥问题了 就这段话: 从某张表中查询数据 先经过where条件筛选出有价值的数据 对这些有价值的数据进行分组 分组之后可以使用having继续筛选 Select把结果显示出来 最后排序输出 条例很清晰 老杜MYSQL P41~46也讲了这些问题 还有 Distinct 也能用这种分析解释 `select distinct 职称 from 教师` 查有哪几种职称 假如1、2、3、4 `select distinct 性别 from 教师` 查有哪几种性别 男女 只保留一个 有相同就去掉 `select distinct 性别,职称 from 教师` 把性别和职称合并 两个都一样才叫重复 跟主键和唯一性约束很像 所以就不能 `select 性别,distinct 职称 from 教师` 会报错 Distinct 职称后 还剩4个字段 性别有多少个是跟表里面一样多的 它并没有去重 所以数量都不匹配 无意义 所以报错 --- ⬅️ [[11-聚合查询|11-聚合查询]] 🏠 [[00-数据库|00-数据库]] ➡️ [[13-多表连接查询|13-多表连接查询]]