【问题标题】:For each employee in employee table, find number of direct and indirect bosses in hierarchy对于员工表中的每个员工,查找层次结构中直接和间接老板的数量
【发布时间】:2019-11-14 08:25:25
【问题描述】:

我得到了一个如下所示的员工表:

用于创建示例输入的查询。

CREATE TABLE employee(
    empId INTEGER,
    empName VARCHAR(20),
    mgrId INTEGER,
    salary DECIMAL(12,2)
);

INSERT INTO employee VALUES
(1, 'A', 2, 100),
(2, 'B', 4, 150),
(3, 'C', 4, 165),
(4, 'D', 7, 200),
(5, 'E', 6, 210),
(6, 'F', 7, 250),
(7, 'G', 7, 300),
(8, 'H', 6, 170);

链接到 SQL Fiddle:http://sqlfiddle.com/#!9/cd4be8

此示例数据导致此层次结构。

每个员工都有一个直接上司。此外,所有比给定员工高级的员工都被称为他们的间接老板。 在给定的样本中,A 的直接老板是 B,C、D、E、F、G 和 H 是 A 的间接老板。我需要找到两件事。

  1. 对于每个员工,找出比该员工高的所有员工的数量(直接上司人数 + 间接上司人数)。

预期输出:

+---------+-------+
| empName | total |
+---------+-------+
| A       |     7 |
| B       |     3 |
| C       |     3 |
| D       |     1 |
| E       |     3 |
| F       |     1 |
| G       |     0 |
| H       |     3 |
+---------+-------+
  1. 对于每个员工,找到间接老板的方式是间接老板的工资至少是给定员工工资的两倍,但在间接老板中最低。

预期输出:

+---------+------+
| empName | mgr  |
+---------+------+
| A       | D    |
| B       | G    |
| C       | NULL |
| D       | NULL |
| E       | NULL |
| F       | NULL |
| G       | NULL |
| H       | NULL |
+---------+------+

解释:对于员工 A(工资 = 100),至少双倍工资的间接老板是 D(工资 = 200)、F(工资 = 210)和 G(工资 = 300)。但由于 D 的工资是 D、F 和 G 最低的,所以结果是 D。

很容易找到员工的下属人数,但反过来却非常棘手。任何帮助/提示将不胜感激。

【问题讨论】:

  • 找老板的数量和找员工下属的数量一样简单,如果你已经有这个,请分享一下,我们可以告诉你要切换哪两个别名反转方向。如果您需要灵感(也就是基本上所有方法的列表),请参阅How to create a MySQL hierarchical recursive query
  • 你使用的是哪个版本的 MySQL - 这在 8+ 中大大简化了
  • @Strawberry,我在一次采访中被问到这个问题。目前,我在 MySQL V 5.6 上进行了尝试,但您也可以在 V 8+ 中解释相同的内容,因为我了解自此版本起引入了 Windowing/Analytical 功能(以及其他功能)。我所能尝试的就是这个,然后我被卡住了 - sqlfiddle.com/#!9/cd4be8/13
  • @Solarflare,看起来CTE 是关键。感谢您的提醒。
  • 您可以通过使用闭包表在不使用 CTE 的情况下解决此问题 - 如 stackoverflow.com/a/38701519/5962802 中所述,该代码适用于 PostgreSQL,但对于 MySQL 修改它并不难。闭包表占用磁盘空间但允许更简单的查询 - 仅查找直接祖先/后代、所有可能的后代、直到根的所有祖先、所有兄弟姐妹等。

标签: mysql sql hierarchy


【解决方案1】:

希望在找到更优化的解决方案之前,以下答案会对您有所帮助。

第一步创建一个记录员工级别的新视图。在这种情况下,名为 G 的“老板”的值最小为 1。而员工的每个级别的排名都在增加,A 的最高为 4。视图是使用分层查询构造的,即here

创建视图后,第一个问题通过对所有较高级别的员工求和来回答。对每个等级都执行此操作,并且连接会将信息带到最终视图。

第二个问题以更暴力的方式回答。执行自联接以生成员工和老板的所有可行组合。然后产生老板工资最低的行。

--Creating a view with the level of the diagram
CREATE VIEW MyCTEView 
AS 
    WITH my_anchor AS (
        SELECT boss.[empId], boss.[empName], boss.[mgrId], 1 AS EmpLevel
        FROM [MySchema].[dbo].[employee] AS boss
        WHERE boss.[mgrId]=boss.[empId]

        UNION ALL

        SELECT Emp.[empId], Emp.[empName], Emp.[mgrId], EL.EmpLevel+1
        FROM [MySchema].[dbo].[employee] AS Emp
        INNER JOIN my_anchor as EL
        ON Emp.[mgrId] = EL.[empId]
        WHERE Emp.[mgrId]<>Emp.[empId]
        )
    SELECT * FROM my_anchor;


--Answer to the first question
SELECT A.[empName]
      ,temp.direct_and_indirect-1 AS your_total
FROM [MySchema].[dbo].[MyCTEView] AS A
LEFT JOIN (
SELECT [EmpLevel],SUM(direct_subortinates) OVER(ORDER BY [EmpLevel]) AS direct_and_indirect
FROM (SELECT COUNT([mgrId]) AS direct_subortinates,[EmpLevel]
            FROM [MySchema].[dbo].[MyCTEView] GROUP BY [EmpLevel])T) AS Temp
ON Temp.[EmpLevel]=A.[EmpLevel]
ORDER BY A.[empName]


--Answer to the second question. Creating a CTE with all the viable combinations of employee and manager based on criteria.
--Displaying the information for the minimum
WITH cte AS (
SELECT A.[empId] as emId
      ,A.[empName] as emName
      ,A.[salary] as emsalary
      ,A.[EmpLevel] as emLevel
      ,B.[empId] as bossId
      ,B.[empName] as bossName
      ,B.[salary] as bosssalary
      ,B.[EmpLevel] as bossLevel
  FROM [MySchema].[dbo].[MyCTEView] AS A
  INNER JOIN 
  [MySchema].[dbo].[MyCTEView] AS B
  ON A.empId<>B.empId AND A.[EmpLevel]>B.[EmpLevel] AND B.[salary]>=2*A.[salary]
  )
SELECT tb1.emName, tb1.bossName 
FROM cte AS tb1
  INNER JOIN
  (
    SELECT emName, MIN(bosssalary) MinSalary
    FROM cte
    GROUP BY emName
  )tb2
  ON  tb1.emName=tb2.emName
  WHERE tb1.bosssalary=tb2.MinSalary

【讨论】:

  • 非常感谢您提供此解决方案。它就像一个魅力。我真正喜欢的是你在解释你的方法时所涵盖的细节。再次感谢!干杯!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-16
相关资源
最近更新 更多