编写一个 SQL 查询,获取 Employee 表中第二高的薪水(Salary) 。
例如下述 Employee 表,SQL查询应该返回 200 作为第二高的薪水。如果不存在第二高的薪水,那么查询应返回 null。
+----+--------+ +---------------------+
| Id | Salary | | SecondHighestSalary |
+----+--------+ +---------------------+
| 1 | 100 | | 200 |
| 2 | 200 | +---------------------+
| 3 | 300 |
+----+--------+
不考虑返回null:distinct去重、order by排序、desc降序、limit限制返回记录数(第一个参数:行的偏移量(从0开始,0表示第一个),第二个参数:行数)
select distinct salary as SecondHighestSalary
from Employee
order by salary desc limit 1,1
考虑返回null:使用临时表、使用IFNULL
# limit 2,1 等价于 limit 1 offset 2
select (
select distinct salary
from Employee
order by salary desc limit 1,1
) as SecondHighestSalary
select IFNULL((
select distinct salary
from Employee
order by salary desc limit 1 offset 1),NULL)
as SecondHighestSalary
#找到最大的
select max(distinct salary) from Employee
#找到第二大的
select max(distinct salary) from Employee where salary <(select max(distinct salary) from Employee
#
select IFNULL((select max(distinct salary) from Employee where salary <(select max(distinct salary) from Employee)),NULL) as SecondHighestSalary
编写一个 SQL 查询,获取 Employee 表中第 n 高的薪水(Salary)。
+----+--------+
| Id | Salary |
+----+--------+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
+----+--------+
CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
SET N = N - 1;
RETURN (
# Write your MySQL query statement below.
select IFNULL((select distinct salary from Employee order by salary desc limit 1 offset N),NULL)
);
END
SELECT DISTINCT e.salary
FROM employee e
WHERE (SELECT count(DISTINCT salary) FROM employee WHERE salary>e.salary) = N-1
SELECT DISTINCT e1.salary
FROM employee e1 LEFT JOIN employee e2 ON e1.salary < e2.salary
GROUP BY e1.salary
HAVING count(DISTINCT e2.salary) = N-1
SELECT DISTINCT e1.salary
FROM employee e1, employee e2
WHERE e1.salary <= e2.salary
GROUP BY e1.salary
HAVING count(DISTINCT e2.salary) = N
SELECT DISTINCT salary
FROM (
SELECT salary, @r:=IF(@p=salary, @r, @r+1) AS rnk, @p:= salary
FROM employee, (SELECT @r:=0, @p:=NULL)init
ORDER BY salary DESC
) tmp
WHERE rnk = N
Scores 表:查询结果按分数从高到低排列
+----+-------+ +-------+------+
| Id | Score | | Score | MyRank |
+----+-------+ +-------+------+
| 1 | 3.50 | | 4.00 | 1 |
| 2 | 3.65 | | 4.00 | 1 |
| 3 | 4.00 | | 3.85 | 2 |
| 4 | 3.85 | | 3.65 | 3 |
| 5 | 4.00 | | 3.65 | 3 |
| 6 | 3.65 | | 3.50 | 4 |
+----+-------+ +-------+------+
思路:
# 第一列
select a.Score as Score from Scores a order by a.Score DESC
# 第二列
select count(distinct b.Score) from Scores b where b.Score >= X as MyRank
# 合并
select
a.Score as Score,
(select count(distinct b.Score) from Scores b where b.Score >= a.Score) as MyRank
from Scores a
order by a.Score DESC
# 或者
select s1.Score,count(distinct(s2.score)) MyRank
from Scores s1,Scores s2
where s1.score<=s2.score
group by s1.Id
order by MyRank
# 或者
select s1.Score,count(distinct(s2.score)) MyRank
from Scores s1 join Scores s2
on s1.score<=s2.score
group by s1.Id
order by s1.Score desc;
问题:相当于2遍select,慢
优化:使用内部变量
SELECT Score,
CAST(CASE
WHEN @pre = Score THEN @rk + 0 # 这里的=是比较运算符
WHEN @pre := Score THEN @rk := @rk + 1
ELSE @rk := @rk + 1
END AS SIGNED)
AS MyRank
FROM Scores, (SELECT @pre := NULL, @rk := 0) AS init # 变量初始化
ORDER BY Score DESC;
优化:使用窗口函数(MySQL8.0以上版本)
SELECT Score,
# rank() OVER(ORDER BY Score DESC) AS MyRank
DENSE_RANK() OVER(ORDER BY Score DESC) AS MyRank
# row_number() OVER(ORDER BY Score DESC) AS MyRank
FROM Scores
使用rank() 使用DENSE_RANK() 使用row_number()
+-------+------+ +-------+------+ +-------+------+
| Score | Rank | | Score | Rank | | Score | Rank |
+-------+------+ +-------+------+ +-------+------+
| 4.00 | 1 | | 4.00 | 1 | | 4.00 | 1 |
| 4.00 | 1 | | 4.00 | 1 | | 4.00 | 2 |
| 3.85 | 3 | | 3.85 | 2 | | 3.85 | 3 |
| 3.65 | 4 | | 3.65 | 3 | | 3.65 | 4 |
| 3.65 | 4 | | 3.65 | 3 | | 3.65 | 5 |
| 3.50 | 6 | | 3.50 | 4 | | 3.50 | 6 |
+-------+------+ +-------+------+ +-------+------+