2016-12-21 15 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より前)では、すべての親子ペアが取得されます。再帰的な部分(UNION ALLの後)では、各ペアの次のレベルの子を取得し、それをParent-Childペアの代わりにParent-Childペアに置き換えます。

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

関連する問題