【问题标题】:SQL Server parent child (parent see all everything)?SQL Server 父子(父查看所有内容)?
【发布时间】:2017-05-06 15:25:13
【问题描述】:

这是我的桌子:

EmployeeID  Employee    ManagerID
---------------------------------
    1       Anna           5
    2       John           4
    3       Steve          4
    4       Lisa           1
    5       Adam          NULL
    6       Per            1

通过这样的自加入来获得父子关系对我来说没有问题:

SELECT 
    E.EmployeeID,
    E.Employee AS Employee,
    E.ManagerID,
    M.Employee AS Manager
FROM 
    Employee AS E
LEFT JOIN 
    Employee AS M ON E.ManagerID = M.EmployeeID

EmployeeID  Employee    ManagerID   Manager
1   Anna    5   Adam
2   John    4   Lisa
3   Steve   4   Lisa
4   Lisa    1   Anna
5   Adam    NULL NULL
6   Per     1    Anna

但是,我将如何确保父级看到整个层次结构?

我希望表格如下所示:

EmployeeID  Manager Employee    EmployeeID  
5   Adam    Anna    1
5   Adam    Per     6
5   Adam    Lisa    4
5   Adam    John    2
5   Adam    Steve   3
1   Anna    Per     6
1   Anna    Lisa    4
1   Anna    John    2
1   Anna    Steve   3
4   Lisa    John    2
4   Lisa    Steve   3

注意:在这个例子中我只有 3 个级别的管理器,但可以有更多

【问题讨论】:

  • SQL Server 对此有一个 hierarchyId 类型。
  • 另一种方法是使用recursive CTE。根据记录数和级别数,您可能会发现此方法有点慢。
  • 嗨,是的,我一直在研究递归 CTE,但不完全了解如何在不了解关卡的情况下使用它。你有这个问题的例子吗?

标签: sql-server tsql parent-child hierarchy


【解决方案1】:

你可以试试这个:

DECLARE @DataSource TABLE
(
    [EmployeeID] TINYINT
   ,[Employee] VARCHAR(12)
   ,[ManagerID] TINYINT 
);

INSERT INTO @DataSource ([EmployeeID], [Employee], [ManagerID])
VALUES (1, 'Anna', 5)
      ,(2, 'John', 4)
      ,(3, 'Steve', 4)
      ,(4, 'Lisa', 1)
      ,(5, 'Adam', NULL)
      ,(6, 'Per',  1);

WITH DataSource AS 
(
    SELECT DISTINCT DS1.*
                   ,0 AS [Level]
                   ,DS1.[EmployeeID] AS Parent
    FROM @DataSource DS1
    INNER JOIN @DataSource DS2
        ON DS1.[EmployeeID] = DS2.[ManagerID]
    UNION ALL
    SELECT DS2.*
          ,DS1.[Level] + 1
          ,DS1.Parent
    FROM DataSource DS1
    INNER JOIN @DataSource DS2
        ON DS1.[EmployeeID] = DS2.[ManagerID]
)
SELECT DS1.[EmployeeID] 
      ,DS1.[Employee] AS [Manager]
      ,DS.[EmployeeID]
      ,DS.[Employee]
FROM DataSource DS
INNER JOIN @DataSource DS1
    ON DS.[Parent] = DS1.[EmployeeID]
WHERE DS.[Level] <> 0
ORDER BY DS.[Parent] DESC;

我们正在使用递归 CTE,如果您第一次看到这种语法,它可能看起来有点凌乱和复杂,但这并没有什么特别之处。

在使用递归 CTE 时,请运行一些性能测试,以确保它是解决问题的正确技术。

【讨论】:

    【解决方案2】:

    您应该使用递归 CTE 语法。在第一次迭代中(在 UNION ALL 之前),您将获得所有父子对。在递归部分(在 UNION ALL 之后),您为每一对获取下一级子级,并将其替换为父子对,而不是子级使父级保持不变。

    WITH CTE AS 
    (
       SELECT TP.EmployeeID as ManagerId, 
              TP.Employee as Manager,
              TC.EmployeeID as EmployeeID, 
              TC.Employee as Employee
    
              FROM TEmployee as TP
              JOIN TEmployee as TC on (TP.EmployeeID = TC.ManagerID)
    
              UNION ALL
    
       SELECT TP.ManagerId as ManagerId, 
              TP.Manager as Manager,
              TC.EmployeeID as EmployeeID, 
              TC.Employee as Employee
    
              FROM CTE as TP
              JOIN TEmployee as TC on (TP.EmployeeID = TC.ManagerID)
    )
    SELECT * FROM CTE Order By ManagerID
    

    结果:

    +-----------+---------+------------+----------+
    | ManagerId | Manager | EmployeeID | Employee |
    +-----------+---------+------------+----------+
    |         1 | Anna    |          4 | Lisa     |
    |         1 | Anna    |          6 | Per      |
    |         1 | Anna    |          2 | John     |
    |         1 | Anna    |          3 | Steve    |
    |         4 | Lisa    |          2 | John     |
    |         4 | Lisa    |          3 | Steve    |
    |         5 | Adam    |          1 | Anna     |
    |         5 | Adam    |          4 | Lisa     |
    |         5 | Adam    |          6 | Per      |
    |         5 | Adam    |          2 | John     |
    |         5 | Adam    |          3 | Steve    |
    +-----------+---------+------------+----------+
    

    【讨论】:

    • 这是完美的,递归CTE在这里真的派上用场了,谢谢。我会将您和@gotqn 的答案标记为正确,因为他是第一个回答的。然而,这是一个很好的解释。
    猜你喜欢
    • 2018-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-19
    相关资源
    最近更新 更多