求TOP N 排名问题
# 177. 第N高的薪水(难度:<font color=orange>**中等**</font>)
编写一个 SQL 查询,获取 Employee 表中第 n 高的薪水(Salary)。
|Id|Salary|
|-|-|
|1|100|
|2|200|
|3|300|
例如上述 Employee 表,n = 2 时,应返回第二高的薪水 200。如果不存在第 n 高的薪水,那么查询应返回 null。
|getNthHighestSalary(2)|
|-|
|200|
**解法:**
**(1)limit+offset**
```SQL
CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
SET N := N-1;
RETURN (
# Write your MySQL query statement below.
SELECT
salary
FROM
employee
GROUP BY
salary
ORDER BY
salary DESC
LIMIT N, 1
);
END
```
**(2)子查询**
```SQL
Select distinct e.salary
From employee e
Where (select count(distinct salary) from employee where salary >e.salary) = N
```
**(3)连接查询**
```SQL
Select distinct e1.salary
From employee e1 join employee e2 on e1.salary <= e2.salary
Group by e1.salary
Having count(distinct e2.salary) = N
```
**(4)笛卡尔积**
```SQL
Select distinct e1.salary
From employee e1, employee e2 where e1.salary <= e2.salary
Group by e1.salary
Having count(distinct e2.salary) = N
```
**(5)自定义变量**
```SQL
Select distinct salary
From (select salary, @r:= if(@p=salary, @r, @r+1) as rank, @p:=salary
From employee ,(select @r:=0, @p:=NULL) init
Order by salary desc) t
Where rank = N
```
**(6)窗口函数**
```SQL
Select distinct salary
From (select salary, dense_rank() over(order by salary desc) as rank from employee)t
Where rank = N
```
**总结:单表 > 连接 (尽量不用子查询、笛卡尔积)**
# 185. 部门工资前三高的所有员工(难度:<font color=red>**困难**</font>)
**Employee** 表包含所有员工信息,每个员工有其对应的工号 **Id**,姓名 **Name**,工资 **Salary** 和部门编号 **DepartmentId** 。
<img src="https://cos.easydoc.net/17082933/files/keh2svb7.png" style="zoom: 85%;" />
编写一个 SQL 查询,找出每个部门获得前三高工资的所有员工。例如,根据上述给定的表,查询结果应返回:
<img src="https://cos.easydoc.net/17082933/files/keh2v39z.png" style="zoom: 85%;" />
**解释:**
IT 部门中,Max 获得了最高的工资,Randy 和 Joe 都拿到了第二高的工资,Will 的工资排第三。销售部门(Sales)只有两名员工,Henry 的工资最高,Sam 的工资排第二。
**(1)自变量** 650 ms
```sql
SELECT dpTable.Name AS Department, Employee, Salary
FROM
(
SELECT Name AS Employee, Salary, DepartmentId,
@rank := IF(@preDepartmentId = DepartmentId, IF(@preSalary = Salary, @rank + 0, @rank + 1), 1) AS SalaryRank,
@preDepartmentId := DepartmentId, @preSalary := Salary
FROM (SELECT * FROM Employee ORDER BY DepartmentId, Salary DESC ), (SELECT @preDepartmentId := NULL, @preSalary := NULL, @rank := 0) AS Init
) AS RankTable
INNER JOIN Department AS dpTable ON RankTable.DepartmentId = dpTable.Id
WHERE SalaryRank <= 3;
```
**(2)子查询** 947 ms
```sql
SELECT d.Name AS 'Department', e1.Name AS 'Employee', e1.Salary
FROM Employee e1
JOIN Department d
ON e1.DepartmentId = d.Id
WHERE
3 > (SELECT COUNT(DISTINCT e2.Salary)
FROM Employee e2
WHERE e2.Salary > e1.Salary AND e1.DepartmentId = e2.DepartmentId
)
;
```
**(3)窗口函数** 563 ms
```sql
select b.name as department,a.name as employee,a.salary as salary
from employee as a , department as b,
( select id,dense_rank() over(partition by departmentid order by salary desc) as rrank from employee ) as c
where a.departmentid = b.id and a.id = c.id and c.rrank in (1,2,3)
```