Loading [MathJax]/jax/input/TeX/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >SQL 找出分组中具有极值的行

SQL 找出分组中具有极值的行

作者头像
白日梦想家
发布于 2020-07-20 03:00:57
发布于 2020-07-20 03:00:57
2.3K00
代码可运行
举报
文章被收录于专栏:SQL实现SQL实现
运行总次数:0
代码可运行

你可能也遇到过这种需求:找出每个部门入职最早的员工的信息;获取每个科目最高分的学生信息;获取用户最近一次的完整登录信息。

这些需求有两个共同点:一是需要做分组,有按部门分组、有按科目、也有按用户分组;二是在分组里面找到存在极值的行,是整行数据,而不只是极值

就拿 emp 举例,要从 emp 表中获取每个部门薪资最高的员工的信息。emp 表的数据如下:

最终的查询结果如下图。

要实现这个查询功能,有多少种实现方法呢?

窗口函数

如果你在用 MySQL 5.8+,窗口函数可能是你最先想到的办法,因为它足够简洁、简单。

先按部门分组,再对组内按照薪资降序排序,取排序序号为 1 的行即为部门最高薪资的员工的信息。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT 
  empno,
  ename,
  job,
  mgr,
  hiredate,
  sal,
  comm,
  deptno 
FROM
  (SELECT 
    *,
    rank() over (
      PARTITION BY deptno 
  ORDER BY sal DESC
  ) AS rk 
  FROM
    emp) t 
WHERE rk = 1 
ORDER BY deptno

这里需要注意,用来排序的窗口函数使用 rank() 或者 dense_rank(),而不能使用 row_number() ,因为有可能存在一个部门里两名或者和更多员工的薪资都是最高的,row_number() 不会给相同的排序条件分配同一个序号。

子查询

如果你的数据库还不支持窗口函数,那可以先对 emp 分组,取出每个部门中的最高薪资,再和原表做一次关联就能获取到正确的结果。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT 
  a.* 
FROM
  emp a 
  INNER JOIN 
    (SELECT 
      deptno,
      MAX(sal) AS sal 
    FROM
      emp 
    GROUP BY deptno) b 
    ON b.deptno = a.deptno 
    AND b.sal = a.sal 
ORDER BY deptno

上面是自然连接的写法,你也可以在WHERE 条件中使用子查询。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT 
  a.* 
FROM
  emp a 
WHERE a.sal = 
  (SELECT 
    MAX(sal) 
  FROM
    emp 
  WHERE deptno = a.deptno) 
ORDER BY deptno

外连接

外连接总能给我们带来惊喜,这次也不例外。

在此之前,你可能很难想到可以使用 Left Join 达到分组求极值的效果。现在就来揭开 Left Join 的神秘面纱。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT 
  a.* 
FROM
  emp a 
  LEFT JOIN emp b 
    ON b.deptno = a.deptno 
    AND a.sal < b.sal 
WHERE b.sal IS NULL 
ORDER BY a.deptno

我们知道,在SELECT * FROM a left join b on 关联条件 语句中 ,不论在 b 表中是否有数据行可以和 a 表匹配,a 表的数据都会查询出来。不过,我们可以通过 WHERE 子句过滤 a 表返回的数据。

在关联条件 b.deptno = a.deptno AND a.sal < b.sal 中,只要 a.sal 不是分组内的最大值,总能在 b 表中找到比它大的数据。当 a.sal 是分组的内的最大值时,a.sal < b.sal 的条件不成立,关联出来的结果中 b 表的数据为 NULL。因此,通过 WHERE b.sal IS NULL 可以找到每个分组里面 a.sal 最大的记录。

总结

前两种方法我们最可能想到,它们的写法也很容易理解,而使用外连接就需要我们多一点反向思考,需要知道使用外连接可以关联出为 NULL 的数据。

上面这几种方法都能满足前文提出的需求,至于它们之间哪个执行更快,就留给读者你去思考了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-05-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 SQL实现 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
模拟 ROW_NUMBER() 函数
MySQL 在 8.0 的版本推出了窗口函数,我们可以很方便地使用 row_number() 函数生成序号。
白日梦想家
2020/07/20
1.2K0
模拟 ROW_NUMBER() 函数
MySQL练习题(一)
-- 1.查询各部门中薪资最低和最高的数据,包括的子段有部门编号、部门名词、员工名称、最高薪资、最第薪资.
兔云小新LM
2019/07/22
1.4K0
SQL理论课-Class 5
EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或False。
OliverHan
2023/02/27
2810
day3 sql语句
sqlplus / as sysdba startup sqlplus scott/tiger vi .bash_profile 容宽不够 set lines 200 set pages 200 确定数据量: select count(*) from emp; (1) select count(1) from emp; (2) 确定表结构 desc emp; 看两行 select empno,ename from emp; 可以进行数学运算 select empno,ename,sal
98k
2018/04/12
7070
MySQL经典33题,DQL语句硬核专项练习!!!
第二步:将第一步的表当作临时表与emp表做连接 连接条件e.deptno=t.deptno and e.sal=t.maxsal
百思不得小赵
2022/12/01
6950
MySQL经典33题,DQL语句硬核专项练习!!!
SQL 窗口函数
MYSQL 从 8.0.2 版本起开始支持窗口函数,那么在窗口函数没出来之前,我们要实现类似的功能该怎么做呢?
白日梦想家
2020/07/18
8090
SQL 窗口函数
MySQL经典练习题+解题思路(四)
CSDN话题挑战赛第2期 参赛话题:学习笔记 个人主页:BoBooY的CSDN博客_Java领域博主 前言:在上一期中我们讲解了MySQL的入门知识点,但理论总还是要通过实践来印证,学了再多不练也是白费,这一期我们讲解MySQL的一些经典查询例题帮助大家巩固已学知识点,如在做题过程中有知识点的遗忘,可以参考往期文章: MySQL入门知识点(上):https://blog.csdn.net/qq_58233406/article/details/127143537 MySQL入门知识点(下):h
啵啵鱼
2022/11/23
4010
MySQL经典练习题+解题思路(四)
MySQL经典练习题+解题思路(三)
CSDN话题挑战赛第2期 参赛话题:学习笔记 个人主页:BoBooY的CSDN博客_Java领域博主 前言:在上一期中我们讲解了MySQL的入门知识点,但理论总还是要通过实践来印证,学了再多不练也是白费,这一期我们讲解MySQL的一些经典查询例题帮助大家巩固已学知识点,如在做题过程中有知识点的遗忘,可以参考往期文章: MySQL入门知识点(上):https://blog.csdn.net/qq_58233406/article/details/127143537 MySQL入门知识点(下)
啵啵鱼
2022/11/23
5790
MySQL经典练习题+解题思路(三)
Oracle 数据库查询专题 (select * from emmmm 80 T)
传送门: Oracle数据库学习笔记 (四 —— select 从入门到放弃 【上】) Oracle数据库学习笔记 (四 —— select 从入门到放弃 【下】)
Gorit
2021/12/09
5210
MySQL面试题(二)
-- 9.查询出emp表中,部门名称、部门编号并且工作内容为clerk的员工名称和员工岗位.
兔云小新LM
2019/07/22
5260
【MySQL】MySQL的视图
视图(view)是一个虚拟表,非真实存在,其本质是根据SQL语句获取动态的数据集,并为其命
陶然同学
2023/02/24
4.9K0
2024Mysql And Redis基础与进阶操作系列(8)作者——LJS[含MySQL 创建、修改、跟新、重命名、删除视图等具体详步骤;注意点及常见报错问题所对应的解决方法]
MySQL中通过CREATE OR REPLACE VIEW语句和ALTER VIEW语句来修改视图。
盛透侧视攻城狮
2024/10/22
1490
MySQL经典练习题+解题思路(一)
(2)再将查询结果当做一张临时表,与emp表进行表连接(因为有的最高薪水是相同的人,需要将他们都显示出来)
啵啵鱼
2022/11/23
6930
MySQL经典练习题+解题思路(一)
Oracle查询优化-03操作多个表
要将来自多个表的数据组织到一起,就像将一个结果集叠加到另外一个上面一样。 这些表不必有相同的关键字,但是他们对应列的数据类型必须相同。
小小工匠
2021/08/16
3.3K0
Oracle分组函数之ROLLUP用法
rollup函数 本博客简单介绍一下oracle分组函数之rollup的用法,rollup函数常用于分组统计,也是属于oracle分析函数的一种
SmileNicky
2019/07/08
1.5K0
MySQL常用的查询语句(记一次数据库作业)
请按要求用sql语句完成下列题目: (1)列出薪水最高的前三名员工 (2)列出薪水比“ALLEN”高的所有员工信息 (3)计算每个部门的平均薪水 (4)列出哪些人的薪水在部门平均薪水之上 (5)列出平均薪水最高的部门的部门号码 (6)列出每个部门的最高薪水 (7)列出每个部门最高薪水的人员名称 (8)列出所有员工的姓名、薪水、部门名称、薪水等级 (9)列出所有员工及对应领导的名字 (10)列出部门名称和这些部门的员工信息,同时列出那些没有员工的部门 所有查询语句如下 use book; #1.列出薪水最高的前三名员工 select * from emp order by sal desc limit 0,3 ; #2.列出薪水比“ALLEN”高的所有员工信息 SELECT * from emp where sal>(select sal from emp where ename="ALLEN"); #3.计算每个部门的平均薪水 SELECT dept.dname,avg(sal),dept.deptno FROM emp JOIN dept on emp.deptno=dept.deptno GROUP BY dname; #4.列出哪些人的薪水在部门平均薪水之上 select ename,sal,a.deptno from emp a, (select avg(sal) avgsal,deptno from emp group by deptno) b where a.sal > b.avgsal and a.deptno = b.deptno; #5.列出平均薪水最高的部门的部门号码 select a.deptno,MAX(a.avgsal) FROM (SELECT deptno,avg(sal) avgsal FROM emp GROUP BY deptno) a; #6.列出每个部门的最高薪水 SELECT dname,max(sal) sal FROM emp JOIN dept on emp.deptno=dept.deptno GROUP BY dept.dname; #7.列出每个部门最高薪水的人员名称 SELECT dname,ename,max(sal) sal FROM emp JOIN dept on emp.deptno=dept.deptno GROUP BY dept.dname; #8.列出所有员工的姓名、薪水、部门名称、薪水等级 select e1.ename, d.dname, e1.sal, sg.grade from emp e1, emp e2, dept d, salgrade sg where e1.empno = e2.empno and e1.deptno = d.deptno and e1.sal between losal and hisal; #9.列出所有员工及对应领导的名字 select e1.ename '员工',e2.ename '领导' from emp e1, emp e2 where e1.mgr = e2.empno; #10.列出部门名称和这些部门的员工信息,同时列出那些没有员工的部门 SELECT dname,emp.* from emp RIGHT JOIN dept on emp.deptno=dept.deptno
不愿意做鱼的小鲸鱼
2022/09/24
5900
MySQL常用的查询语句(记一次数据库作业)
Oracle之SQL优化专题03-如何看懂SQL的执行计划
专题第一篇《Oracle之SQL优化专题01-查看SQL执行计划的方法》讲到了查看SQL执行计划的方法,并介绍了各种方法的应用场景,那么这一篇就主要介绍下如何看懂SQL的执行计划。毕竟如果SQL的执行计划都看不懂,那优化就无从谈起了。
Alfred Zhao
2020/02/19
7110
Oracle之SQL优化专题02-稳固SQL执行计划的方法
糟糕的SQL执行,执行计划走全表扫描(这里实验直接利用使用hint强制不走索引来模拟这种情况):
Alfred Zhao
2019/05/24
8420
sql语言总结合集
关系型数据库:使用关系模型把数据组织到数据表(table)中。现实世界可以用数据来描述。
全栈程序员站长
2021/12/23
7290
深入解析:半连接与反连接的原理和等价改写方法
半连接的原理及等价改写 1. 什么是半连接 当两张表进行关联,只返回匹配上的数据并且只会返回一张的表的数据,半连接一般就是指的在子查询中出现 IN 和 EXISTS。 执行计划最常见的有下面的两个: NESTED LOOPS SEMI HASH JOIN SEMI 1.1 NESTED LOOP SEMI 执行步骤: 优化器选择主查询中的表为驱动表; 选择子查询中的表为被驱动表; 把驱动表的每一行根据连接列去被驱动表中去查找匹配的行; 如果在被驱动表中匹配上一个或者多个,则返回驱动表中的数据。 HI
数据和云
2018/03/29
2K0
深入解析:半连接与反连接的原理和等价改写方法
相关推荐
模拟 ROW_NUMBER() 函数
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验