23

对所有员工的薪水按照salary进行按照1-N的排名

http://www.nowcoder.com/questionTerminal/b9068bfe5df74276bd015b9729eec4bf

题目:对所有员工的当前(to_date=‘9999-01-01')薪水按照salary进行按照1-N的排名,相同的salary并列且按照emp_no升序排列

错误示范:虽然在题库中能通过,但是在mysql中无法通过,因为s1.salary不是可聚合项
SELECT s1.emp_no, s1.salary, COUNT(DISTINCT s2.salary) AS rank
FROM salaries AS s1, salaries AS s2
WHERE s1.to_date='9999-01-01'
AND s2.to_date='9999-01-01'
AND s1.salary<=s2.salary
GROUP BY s1.emp_no
ORDER BY rank ASC, s1.emp_no ASC;
注意:这里emp_no是聚合项,但不是主键,只是联合主键之一,所以不能唯一确定salary,所以salary实际上是不可聚合的,所以不能放入SELECT。
补充:如果上面的代码中,我们能在WHERE子句中加入s1.from_date的确定性约束条件(如s1.from_date=‘9999-01-01’),这样s1.emp_no确定的时候,s1.salary也就确定了。此时就可以认为s1.salary是可聚合的。

错误示范:COUNT()是错误的,因为对s1.salary<=s2.salary,重复的s2.salary应该只算一个
SELECT a.emp_no, a.salary, b.rank
FROM salaries AS a
INNER JOIN(SELECT s1.emp_no, COUNT(
) AS rank
FROM salaries AS s1, salaries AS s2
WHERE s1.to_date='9999-01-01'
AND s2.to_date='9999-01-01'
AND s1.salary<=s2.salary
GROUP BY s1.emp_no) AS b
ON a.emp_no=b.emp_no
AND a.to_date='9999-01-01'
ORDER BY a.salary DESC, a.emp_no ASC;

方法1:先构建不含salary的rank表,再将rank表和salaries表内接,然后排序得到结果
SELECT a.emp_no, a.salary, b.rank
FROM salaries AS a
INNER JOIN(SELECT s1.emp_no, COUNT(DISTINCT s2.salary) AS rank
FROM salaries AS s1, salaries AS s2
WHERE s1.to_date='9999-01-01'
AND s2.to_date='9999-01-01'
AND s1.salary<=s2.salary
GROUP BY s1.emp_no) AS b
ON a.emp_no=b.emp_no
AND a.to_date='9999-01-01'
ORDER BY a.salary DESC, a.emp_no ASC;

方法2:固定s1的一条记录,利用关联查询的到它的rank
SELECT s1.emp_no, s1.salary,
(SELECT COUNT(DISTINCT s2.salary)
FROM salaries AS s2
WHERE s2.to_date='9999-01-01'
AND s2.salary>=s1.salary
) AS rank
FROM salaries AS s1
WHERE s1.to_date='9999-01-01'
ORDER BY s1.salary DESC, s1.emp_no ASC

方法3:SQL编程,在题库中不能运行,在mysql中可以运行
SELECT emp_no, salary,
@rankno := @rankno + (@pre <> (@pre := salary)) AS rank
FROM salaries, (SELECT @rankno := 0, @pre := -1) AS r
WHERE to_date = '9999-01-01'
ORDER BY salary DESC;
解析:变量使用前要加@,:=表示赋值,(SELECT @rankno := 0, @pre := -1) r是进行初始化,r是推导表的别名,
@rankno代表排名,@pre代表工资,@rankno := @rankno + (@pre <> (@pre := salary)) rank是推导公式,rank是别名
@pre <> (@pre := salary)的执行顺序是:
@pre是上一次的值
@pre:=salary是进行新一次赋值给pre
判断<>,如果左右不想等,则返回1,否则(相等)返回0
SQL编程没找到更多的资料,所以只能就题论题了,不建议在不熟悉的情况下使用。可以作为了解。

全部评论
我每次看这个老兄的答案都觉得很痛苦又觉得很牛逼
7 回复 分享
发布于 2021-02-02 23:37
SQL的题下到处都是这位大佬
1 回复 分享
发布于 2021-05-16 16:19
最后在排序那里 emp_no改成s1.emp_no就能通过了
1 回复 分享
发布于 2020-10-19 17:21
把方法3中的'<>'用CASE表达式替换就可以正常在题库中运行
1 回复 分享
发布于 2021-03-19 19:11
mysql8.0吧rank改成ranks就可以跑了
点赞 回复 分享
发布于 2021-05-03 17:14
看了半天发现看了一个错的方法,很牛逼,但是看起来很费劲
点赞 回复 分享
发布于 2021-04-14 13:06
你们用的方法一跑的通吗
点赞 回复 分享
发布于 2020-12-03 16:01
想知道为啥我这样写不通过呢?我在mysql中就查出来了 SELECT s1.emp_no, s1.salary, COUNT(DISTINCT s2.salary) AS rank FROM salaries AS s1, salaries AS s2 WHERE s1.to_date = '9999-01-01' AND s2.to_date = '9999-01-01' AND s1.salary <= s2.salary GROUP BY s1.emp_no ORDER BY s1.salary DESC, emp_no
点赞 回复 分享
发布于 2020-08-17 18:44
请教方法3中怎么体现的emp_no的排序?谢谢
点赞 回复 分享
发布于 2020-07-05 11:29
为什么方法二中rank查询,不需要加group by呢
点赞 回复 分享
发布于 2020-05-30 11:06

相关推荐

程序员花海:实习和校招简历正确格式应该是教育背景+实习+项目经历+个人评价 其中项目经历注意要体现业务 实习经历里面的业务更是要自圆其说 简历模板尽可能保持干净整洁 不要太花哨的
秋招吐槽大会
点赞 评论 收藏
分享
评论
31
5
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务