MySQL - 将 table 加入自身/子查询

MySQL - joining a table to itself / sub queries

我正在就一个我最近做错的评估问题寻求帮助,我已经尝试了很多解决方案并且我认为我有点知道我正在尝试做什么,但似乎无法弄清楚语法。

我有一个 table 看起来像下面但有更多记录。

MyTable
ID   Name            DivisionID   ManagerID   Salary
123  John Smith      100          789         40000
456  Harold Johnson  101          null        60000
789  Vicky Brown     100          null        80000

并且必须 select 薪水第三高的人的行,我没有问题。但是,我还需要return,而不是ManagerID,Manager Name,需要从同一个table.

中查找

我尝试了以下解决方案,它似乎有点不雅,并且必须在其中硬编码相同的查询,因此不适合扩展或一般用途:

SELECT 
table.ID, 
Name,
DivisionID,
(SELECT 
    Name FROM table WHERE id=(
        SELECT ManagerID FROM table ORDER BY Salary DESC LIMIT 2,1)
) AS ManagerName,
Salary

FROM table
ORDER BY Salary DESC LIMIT 2,1;

我认为可能有一些方法可以用子查询来做到这一点,例如首先 selecting 一个单独的 table 在仅经理 ID 和名称的查询中,然后 selecting 从这个 - 但我似乎无法获得正确的语法或得到我的绕过它。我认为 table 别名也有可能,我 select 来自同一 table 的两个不同结果在不同的别名下,然后将两者结合起来,但同样无法弄清楚如何去做这个。以下是我尝试使用别名

所做的
SELECT 
a.ID, 
a.Name,
a.DivisionID,
b.Name AS ManagerName
a.Salary

FROM table a
INNER JOIN table b ON a.ManagerID=b.ID
ORDER BY Salary DESC LIMIT 2,1;

首先,当被问到return第n个greatest/least值时,一定要问回来,万一平局怎么办。他们想要薪水第三高的人,所以薪水为 1000、1000、900、900、800、800、700、600、500,我想你想要 return 收入 800 的人,因为那是第三高的薪水。如果只按薪水排序,跳二取第三,那你随便挑一个900的人,900连第三都不是,而是第二高

要获得经理,只需再次加入table即可。如果工资第三高的员工本身就是经理,你应该使用外部连接。

straight-forward 解决方案是对具有 DENSE_RANK 的行进行排名:

select *
from
(
  select t.*, dense_rank() over (order by salary desc) as rnk
  from mytable t
) employee
left join mytable manager on manager.id = employee.managerid
where employee.rnk = 3;

MySQL 自版本 8 起支持 DENSE_RANK。在旧版本中,您必须再次查找相同的 table。 Select 不同的工资并在这些销售上使用你的 limit/offset 条款。

select *
from mytable employee
left join mytable manager on manager.id = employee.managerid
where employee.salary =
(
  select distinct salary
  from mytable
  order by salary desc
  limit 2, 1
);

演示:https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=6b17e369fcd4f99ddc6c268de15f08a1

Maka 子查询来自你的第三个代码并加入 selj 加入 table

这也适用于 MySQL 5.7 及更早版本

CREATE TABLE MyTable (
  `ID` INTEGER,
  `Name` VARCHAR(14),
  `DivisionID` INTEGER,
  `ManagerID` VARCHAR(4),
  `Salary` INTEGER
);

INSERT INTO MyTable
  (`ID`, `Name`, `DivisionID`, `ManagerID`, `Salary`)
VALUES
  ('123', 'John Smith', '100', '789', '40000'),
  ('456', 'Harold Johnson', '101', 'null', '60000'),
  ('789', 'Vicky Brown', '100', 'null', '80000');
SELECT m1.ID, m1.Name, m1. DivisionID,m2. Name, m1.Salary 
FROM (SELECT `ID`, `Name`, `DivisionID`, `ManagerID`, `Salary` FROM MyTable ORDER BY Salary DESC LIMIT 2,1) m1 JOIN MyTable m2 on m1.ManagerID = m2.ID
 ID | Name       | DivisionID | Name        | Salary
--: | :--------- | ---------: | :---------- | -----:
123 | John Smith |        100 | Vicky Brown |  40000

db<>fiddle here