2016-12-21 5 views
3

Это мой стол:Родительский родитель SQL Server (родительский видит все)?

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 уровня сене, но может быть гораздо больше

+2

SQL Server имеет тип hierarchyid' в течение этого. –

+1

Альтернативный подход заключается в использовании [рекурсивного CTE] (https://technet.microsoft.com/en-us/library/ms186243%28v=sql.105%29.aspx?f=255&MSPPError=-2147217396). В зависимости от количества записей и количества уровней вы можете обнаружить, что этот метод будет немного медленным. –

+0

Привет, Да, я смотрел рекурсивный CTE, но не полностью понял, как использовать его без знания уровней. У вас есть пример этого вопроса, из которого я могу перейти? – Nils

ответ

2

Вы можете попробовать это:

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; 

enter image description here

Мы используем рекурсивный CTE, и он может выглядеть не совсем грязным и сложным, если вы впервые видите этот синтаксис, но это ничего особенного.

Когда используются рекурсивные CTE, выполняйте некоторые тесты производительности, чтобы быть уверенными, что это правильный метод решения вашей проблемы.

1

Вы должны использовать рекурсивный синтаксис CTE. На первой итерации (до UNION ALL) вы получаете все пары Parent-Child. В рекурсивной части (после UNION ALL) вы получаете ребенка следующего уровня для каждой пары и заменяете его на пару Parent-Child вместо Child, оставляя Parent одинаково.

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 | 
+-----------+---------+------------+----------+ 
+0

Это прекрасно, рекурсивный CTE действительно пригодится здесь, спасибо. Я буду отмечать ваши ответы и @gotqn как правильные, потому что он первым ответил. Однако это ответ - отличное объяснение. – Nils