SQL面试题---topN问题

topN问题是SQL面试里经常考的一个问题,即如何取每组最大的N条记录。

这里摘取leetcode上的一道题,因为主要为了说明如何选取topN的记录,因此这里删掉了第二张表(不需要进行两表连接)。

题目:根据Employee表中的信息,找出每个部门工资前三高的员工信息(部门号,姓名,工资)

| Id | Name  | Salary | DepartmentId |
+----+-------+--------+--------------+
| 1  | Joe   | 70000  | 1            |
| 2  | Henry | 80000  | 2            |
| 3  | Sam   | 60000  | 2            |
| 4  | Max   | 90000  | 1            |

解法一:使用window function

因为这里需要选取的是前三高的工资,如果工资相同,那么排名并列,因此这里用的窗口函数为dense_rank()。

SELECT DepartmentId, Name, Salary,
FROM (SELECT *,
DENSE_RANK() OVER (PARTTITION BY DepartmentId
ORDER BY Salary DESC) AS rank
FROM Employee)
WHERE rank<=3;

这里需要注意的是:因为where在select之前执行,因此如果直接使用rank进行条件筛选会报错。需要再嵌套一层选择子句,把之前的语句放入from里面,因为from是最先执行的,因此这样就不会报错。

使用窗口函数是比较轻松的解法,但是有些数据库不支持窗口函数,因此很可能面试官会问你,如果不用窗口函数,这题该怎么解?

解法二:使用关联子查询

SELECT e.DepartmentId, e.Name, e.Salary
FROM Employee AS e
WHERE (SELECT COUNT(DISTINCT e2.Salary)
FROM Employee AS e2
WHERE e.DepartmentId=e2.DepartmentId
AND e2.Salary>e.Salary) < 3;

这里的解题思路是,先使用关联子查询把相同部门的员工归在一起,然后条件筛选出比各个员工工资高的员工,如果这些筛选出的员工的数量小于3个,那就说明进行对比的这些员工排在前三位。比如,如果你排在你们部门第一位,那么就有0个人的工资比你高,如果你排在第三位,那么就有2个人的工资比你高。

可以看到,上面关联的两张表其实是相同的两张表,因此也可以用自连接来解题,但是由于此种方式没有关联子查询来得清晰,因此这里就不表了。

原文地址:https://www.cnblogs.com/HuZihu/p/12469204.html