SQL查询出每个项目中经验最丰富的员工

一、题目

​ 有如下两张表:

​ T1201A表:

在这里插入图片描述

​ T1201B表:

在这里插入图片描述

​ 查询出每个项目组中经验最丰富(即experience_years最大)的员工,返回结果如下:

在这里插入图片描述

​ 说明:员工1和员工3均为project_id为1中experience_years最丰富的员工,因为他们的experience_years相等,都为项目1中experience_years最大的。

二、测试数据

​ 为了方便大家测试,SQL建表语句如下:

CREATE TABLE `t1201a` (
  `project_id` int NOT NULL,
  `employee_id` int DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

INSERT INTO T1201A VALUES
(1,1),
(1,2),
(1,3),
(2,1),
(2,4);

CREATE TABLE `t1201b` (
  `employee_id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  `experience_years` int DEFAULT NULL,
  PRIMARY KEY (`employee_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

INSERT INTO T1201B VALUES
(1,'张三',3),
(2,'李四',2),
(3,'王五',3),
(4,'马六',2);
三、思路讲解
  1. 首先分析题目,最后需要输出每个项目组experience_years最大的员工,而且根据题目要求,可能存在多个员工的experience_years一样,所以应该是一个并列排名,此时可以想到已知的函数DENSE_RANK()可以满足这个排名的需求;并且是要按照project_id进行分组的,每个项目都要找出experience_years最大的员工,将experience_years进行倒序排序。根据目前的分析,我可以写出如下SQL:

    SELECT DENSE_RANK() over(PARTITION BY project_id ORDER BY experience_years DESC) myrank
    FROM ?;
    
  2. 可以看到步骤1中SQL的project_id和experience_years显然不是一个表数据,需要的是T1201A表和T1201B表中综合的数据,可以想到需要将两个表join起来,这样就可以拿到两个表里全部的数据了。因此,可以将步骤1中SQL进行完善,写出如下SQL:

    SELECT DENSE_RANK() over(PARTITION BY s.project_id ORDER BY s.experience_years DESC ) myrank,s.* 
    FROM(
        SELECT a.project_id, a.employee_id, b.experience_years 
     	FROM t1201a a 
        JOIN t1201b b 
        ON a.employee_id = b.employee_id 
    ) s
    

    运行此SQL,查询出的结果为:

    在这里插入图片描述

  3. 可以看到现在写出的SQL已经初步满足了需求,按照project_id进行了分组排名,不过和最终需求还是有一些差距的,最终需求只要求显示每组的第一名,现在显示了每组的所有排名,那么,我们就可以继续完善SQL,如下所示:

    SELECT
    	t.project_id,
    	t.employee_id 
    FROM
    	(
    	SELECT
    		DENSE_RANK() over ( PARTITION BY s.project_id ORDER BY s.experience_years DESC ) myrank,
    		s.* 
    	FROM
    		( SELECT a.project_id, a.employee_id, b.experience_years FROM t1201a a JOIN t1201b b ON a.employee_id = b.employee_id ) s 
    	) t 
    WHERE
    	t.myrank = 1
    

    运行此SQL,结果如下所示:

    在这里插入图片描述

    可以看到,最终运行结果,已经符合了需求。

四、优化

我们的任务虽然是完成需求,但是对于SQL的优化也是必不可少的,以上只是为了完成需求不断思考的过程,这样得到的SQL不一定是最好的SQL,可以看得到完成的SQL嵌套了两个子查询。分析SQL发现,最内层的子查询所做的事情只是将两个表的数据联合起来,那么是不是可以进行优化呢?

最终优化的SQL如下所示:

SELECT
	t.project_id,
	t.employee_id 
FROM
	(
	SELECT
		DENSE_RANK() over ( PARTITION BY a.project_id ORDER BY b.experience_years DESC ) myrank,a.*,b.experience_years
	FROM
		t1201a a
		JOIN t1201b b 
		ON a.employee_id = b.employee_id 
	) t 
WHERE
	t.myrank = 1

将SQL进行验证,结果正确。

当然,对于SQL查询来说,只要满足需求,怎么样实现都可以的,毕竟一千个人心里有一千个哈姆雷特,爱咋做咋做,这只是我的想法而已,just do it!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mayz梅子子子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值