来自leetcode的原始问题:
The Employee table holds all employees. Every employee has an Id, and there is also
a column for the department Id.
+----+-------+--------+--------------+
| Id | Name | Salary | DepartmentId |
+----+-------+--------+--------------+
| 1 | Joe | 70000 | 1 |
| 2 | Henry | 80000 | 2 |
| 3 | Sam | 60000 | 2 |
| 4 | Max | 90000 | 1 |
| 5 | Janet | 69000 | 1 |
| 6 | Randy | 85000 | 1 |
+----+-------+--------+--------------+
The Department table holds all departments of the company.
+----+----------+
| Id | Name |
+----+----------+
| 1 | IT |
| 2 | Sales |
+----+----------+
Write a SQL query to find employees who earn the top three salaries in each of the department. For the above tables, your SQL query should return the following rows.
+------------+----------+--------+
| Department | Employee | Salary |
+------------+----------+--------+
| IT | Max | 90000 |
| IT | Randy | 85000 |
| IT | Joe | 70000 |
| Sales | Henry | 80000 |
| Sales | Sam | 60000 |
+------------+----------+--------+
我在线学习了一个解决方案,通过自我加入然后加入部门表。
以下是代码:
SELECT d.Name AS Department, e.Name AS Employee, e.Salary
FROM (SELECT e1.Name, e1.Salary, e1.DepartmentId FROM Employee e1
JOIN Employee e2 WHERE e1.DepartmentId = e2.DepartmentId AND e1.Salary <= e2.Salary
GROUP BY e1.DepartmentId HAVING COUNT(DISTINCT(e2.Salary)) <= 3) e
JOIN Department d
ON e.DepartmentId = d.Id
ORDER BY d.Name, e.Salary DESC
我没有得到正确的结果:
Output:
{"headers": ["Department", "Employee", "Salary"], "values": [["IT", "Joe", 60000]]}
Expected:
{"headers": ["Department", "Employee", "Salary"], "values": [["IT", "Joe", 60000],
["IT", "Max", 60000]]}
但是,当GROUP BY更改为e1.Id时,它会起作用。
我不知道为什么会这样。
答案 0 :(得分:1)
了解复杂查询的快速指南
我建议你不要直接告诉你答案 练习。这样你不仅可以理解这个查询,还可以理解 一种了解未来复杂查询的方法:
第1步:缩进查询
您应该缩进查询,使其看起来如下所示 查询的结构更加明显:
SELECT
d.Name AS Department
, e.Name AS Employee
, e.Salary
FROM
(
SELECT -- L1
e1.Name
, e1.Salary
, e1.DepartmentId
FROM
Employee e1
JOIN Employee e2
WHERE
e1.DepartmentId = e2.DepartmentId
AND e1.Salary <= e2.Salary -- L2
-- GROUP BY e1.DepartmentId -- not working
GROUP BY e1.id -- working -- L3
HAVING COUNT(DISTINCT(e2.Salary)) <= 3 -- L4
) e
JOIN Department d
ON e.DepartmentId = d.Id
ORDER BY d.Name, e.Salary DESC
第2步:尝试从最里面的子查询中了解并向外扩展您的理解
在这种情况下,最里面的子查询是e
(从L1
到L4
)。但
甚至这个子查询也有多个子句,它们构建了一个子句
另一个。所以我首先运行这个非常简单的查询(它是一个自连接,
正如你所说的那样,从L1
到L2
,你看到了什么?
SELECT -- L1
e1.Name
, e1.Salary
, e1.DepartmentId
FROM
Employee e1
JOIN Employee e2
WHERE
e1.DepartmentId = e2.DepartmentId
AND e1.Salary <= e2.Salary -- L2
现在当你看到某些内容(与自我加入的效果相关)时,请尝试 再添加一个子句。在这种情况下尝试L3(和非工作 更换)
-- GROUP BY e1.DepartmentId -- not working
GROUP BY e1.id -- working -- L3
GROUP BY
用于聚合,它将是
奇怪的是在查询中看不到任何聚合函数,然后你
可能会注意到有一个聚合函数(COUNT(DISTINCT(e2.Salary))
)
要在下一步中添加(对于HAVING
子句),您可以
将此函数添加到其中一个选择表达式中以查看内容
它得到的价值。所以,现在尝试这个查询(即添加了L3和L5):
SELECT -- L1
e1.Name
, e1.Salary
, e1.DepartmentId
, COUNT(DISTINCT(e2.Salary)) -- L5
FROM
Employee e1
JOIN Employee e2
WHERE
e1.DepartmentId = e2.DepartmentId
AND e1.Salary <= e2.Salary -- L2
GROUP BY e1.id -- working -- L3
你看到了什么?你看到了GROUP BY
的效果吗?
现在尝试添加一个子句 - L4
- 并查看您是否理解
它做了什么
HAVING COUNT(DISTINCT(e2.Salary)) <= 3 -- L4
到现在为止,您应该了解e
做了什么,现在你把它放在一边
一起查询(从这个答案的最顶部开始的列表),和
你现在明白为什么查询有用吗?
答案 1 :(得分:1)
我使用的解决方案类似于ROW_NUMBER而不是其他DBMS使用的PARTITION。
select @rn := case when @DepartmentId = DepartmentId then @rn + 1 else @rn := 1 end as rn,
Id, Name, Salary, DName,
@DepartmentId := DepartmentId as DepartmentId
from
(select @rn := 0 as rn) r,
(select @DepartmentId := e.DepartmentId as DepartmentId, e.Name, e.Salary, e.Id, d.Name as DName
from employ1 e
inner join depart1 d on d.Id = e.DepartmentId
order by e.DepartmentId, e.Salary desc) es;
这句话返回下一个值:
+----+----+-------+--------+-------+--------------+
| rn | Id | Name | Salary | DName | DepartmentId |
+----+----+-------+--------+-------+--------------+
| 1 | 4 | Max | 90000 | IT | 1 |
+----+----+-------+--------+-------+--------------+
| 2 | 6 | Randy | 85000 | IT | 1 |
+----+----+-------+--------+-------+--------------+
| 3 | 1 | Joe | 70000 | IT | 1 |
+----+----+-------+--------+-------+--------------+
| 4 | 5 | Janet | 69000 | IT | 1 |
+----+----+-------+--------+-------+--------------+
| 1 | 2 | Henry | 80000 | Sales | 2 |
+----+----+-------+--------+-------+--------------+
| 2 | 3 | Sam | 60000 | Sales | 2 |
+----+----+-------+--------+-------+--------------+
正如您所看到的,有一个列可以为每个部门重置它的值。
然后只需获取rn&lt; = 3的行来获取前3个工资。
select DName, Name, Salary
from (
select @rn := case when @DepartmentId = DepartmentId then @rn + 1 else @rn := 1 end as rn,
Id, Name, Salary, DName,
@DepartmentId := DepartmentId as DepartmentId
from
(select @rn := 0 as rn) r,
(select @DepartmentId := e.DepartmentId as DepartmentId, e.Name, e.Salary, e.Id, d.Name as DName
from employ1 e
inner join depart1 d on d.Id = e.DepartmentId
order by e.DepartmentId, e.Salary desc) es
) f
where rn <= 3;
这是最终结果:
+-------+-------+--------+
| DName | Name | Salary |
+-------+-------+--------+
| IT | Max | 90000 |
+-------+-------+--------+
| IT | Randy | 85000 |
+-------+-------+--------+
| IT | Joe | 70000 |
+-------+-------+--------+
| Sales | Henry | 80000 |
+-------+-------+--------+
| Sales | Sam | 60000 |
+-------+-------+--------+
可在此处查看:http://rextester.com/MDK2215
答案 2 :(得分:0)
SELECT
d.name as "Department"
,e1.Name as "Employee"
, e1.Salary as "Salary"
FROM
Employee e1
JOIN Employee e2 JOIN Department d
WHERE
e1.DepartmentId = e2.DepartmentId
AND e1.Salary <= e2.Salary AND d.id = e2.DepartmentId
GROUP BY d.name,e1.id
HAVING COUNT(DISTINCT(e2.Salary)) <= 3
ORDER BY d.name , salary DESC
注意**
Leetcode答案未按承诺输出行。
这是匹配的“预期”答案:
{“标题”:[“部门”,“雇员”,“工资”],“值”:[[“ IT”,“最大”,90000],[“ IT”,“乔”,70000] ,[“ Sales”,“ Henry”,80000],[“ Sales”,“ Sam”,60000]]}
答案 3 :(得分:0)
使用的基本逻辑-
DepartmentId
加入两个表,因为那是两个表中的共同列。DENSE_RANK()
函数PARTITION BY DepartmentId
和ORDER BY Salary DESC
为薪水分配等级,因为我们想要每个部门的前三名薪水。DENSE_RANK()函数将为特定部门中具有相同价值的薪水分配相同的等级。
SELECT details.Department "Department", details.Employee "Employee",
details.Salary "Salary", details.dense_rank AS DENSE_RANK FROM
(SELECT e.Name AS Employee, e.Salary AS Salary, e.DepartmentId, d.Name AS Department, DENSE_RANK() OVER (PARTITION BY e.DepartmentId ORDER BY e.Salary DESC) AS dense_rank
FROM Employee e, Department d
WHERE e.DepartmentId = d.Id) details
WHERE dense_rank <=3;
根据上述查询输出:
["Department", "Employee", "Salary", "DENSE_RANK"]
["IT", "Max", 90000, 1]
["IT", "Joe", 85000, 2] --same rank because same salary
["IT", "Randy", 85000, 2] --same rank because same salary
["IT", "Will", 70000, 3]
["Sales", "Henry", 80000, 1]
["Sales", "Sam", 60000, 2]
在https://github.com/hetalrachh/leetcode/blob/master/Hard/DepartmentTop3Salaries.sql检查实际查询