2012-01-27 2 views
3

사용자 목록이 있습니다. 각 사용자에 대해 필드 ParentId에 의해 정의 된 계층 구조가 있습니다 (사용자 중 일부는 계층 구조 맨 위에 있으며이 필드에는 null이 있음). 나는이 테이블의 구조를 바꾸고 싶지 않고 (테이블에 exaple hierarchyId를 추가한다.) 이 순간 계층 구조에서 모든 사용자 관계 목록을 가져 오는 방법은 무엇입니까?

나는이 테이블이 :
사용자 : 나는 모든 관계의 목록을 만들 필요가

UserId INT NOT NULL, ManagerId INT NULL, other fields 

형태로 그 사용자 간의 사용자 조상과 수준 차이 :

UserId, AncestorId, LevelDifference 

예 :
사용자 테이블에서 :
UserId INT NOT NULL, 관리자 ID INT NULL
1, NULL, (짐)
2,1 (조쉬)
3,2 (제니)

내가 가야 :
사용자 아이디, AncestorId, LevelDifference
2,1,1
3, 2,1
3,1,2 - (Jim은 Jenny의 조상 중 하나입니다.)

누구나 빠른 방법으로 아이디어를 얻었습니까?

+1

버전은 무엇? 2005+에서는 [재귀 CTE] (http://msdn.microsoft.com/en-us/library/ms186243.aspx)를 사용할 수 있습니다. –

+0

죄송합니다, 버전을 잊어 버렸습니다. 2008 년입니다. 누군가가 선조에 속하는지 확인하기 위해 cte를 사용하고 있지만, 모든 사용자 간의 관계를 확인하는 것이 매우 느립니다. 다른 쪽에서 처리하는 방법이 있어야합니다. –

+0

T-SQL 함수가 테이블을 메모리로 만들고 반환 할 수 있습니까? –

답변

3

업데이트 됨 - 귀하가 찾고자하는 내용이어야합니다. 조 스테파넬 리로 재귀 CTE를 사용 는 말했다 :

테이블 구조 :

CREATE TABLE [HR].[Employees](
    [empid] [int] IDENTITY(1,1) NOT NULL, 
    [lastname] [nvarchar](20) NOT NULL, 
    [firstname] [nvarchar](10) NOT NULL, 
    [mgrid] [int] NULL 
); 

샘플 데이터 내가 사용 :

empid  lastname    firstname mgrid 
----------- -------------------- ---------- ----------- 
1   Davis    Sara  NULL 
2   Funk     Don   1 
3   Lew     Judy  2 
4   Peled    Yael  3 
5   Buck     Sven  2 
6   Suurs    Paul  5 
7   King     Russell  5 
8   Cameron    Maria  3 
9   Dolgopyatova   Zoya  5 

쿼리 :

WITH RCTE AS (

    SELECT NULL  AS PrevEmpId, 
      NULL  AS PrevMgrId, 
      E.empid  AS CurEmpId, 
      E.mgrid  AS CurMgrid, 
      0   AS [Level], 
      E.lastname AS LastName, 
      E.firstname AS FirstName  
    FROM HR.Employees AS E 
    WHERE E.mgrid IS NULL 

    UNION ALL 

    SELECT PREV.CurEmpId  AS PrevEmpId, 
      PREV.CurMgrid  AS PrevMgrId, 
      CUR.empid   AS CurEmpId, 
      CUR.mgrid   AS CurMgrId, 
      Prev.Level + 1  AS [Level], 
      CUR.lastname  AS LastName, 
      CUR.firstname  AS FirstName 
    FROM RCTE AS PREV 
    JOIN HR.Employees AS CUR ON CUR.mgrid = PREV.CurEmpId 
),RAnecestors AS (

    SELECT E.empid  AS StartEmpId, 
      NULL  AS PrevEmpId, 
      NULL  AS PrevMgrId, 
      E.empid  AS CurEmpId, 
      E.mgrid  AS CurMgrid, 
      1   AS [LevelDiff], 
      E.lastname AS LastName, 
      E.firstname AS FirstName  
    FROM HR.Employees AS E 

    UNION ALL 

    SELECT PREV.StartEmpId  AS StartEmpId, 
      PREV.CurEmpId  AS PrevEmpId, 
      PREV.CurMgrid  AS PrevMgrId, 
      CUR.empid   AS CurEmpId, 
      CUR.mgrid   AS CurMgrId, 
      Prev.[LevelDiff] + 1 AS [LevelDiff], 
      CUR.lastname   AS LastName, 
      CUR.firstname  AS FirstName 
    FROM RAnecestors AS PREV 
    JOIN HR.Employees AS CUR ON CUR.empid = PREV.CurMgrid 
) 
SELECT RCTE.CurEmpId   AS CurrentID, 
     RCTE.LastName   AS CurrentLastName, 
     RAnecestors.CurEmpId AS AncestorID, 
     RAnecestors.LastName AS AncestorLastName, 
     [Level]     AS [Level], 
     [LevelDiff] - 1   AS [LevelDiff] 
LEFT JOIN RAnecestors ON RAnecestors.StartEmpId = RCTE.CurEmpId 
     AND RCTE.CurEmpId <> RAnecestors.CurEmpId 
ORDER BY RCTE.CurEmpId, RAnecestors.LevelDiff 

출력 : SQL 서버의

CurrentID CurrentLastName  AncestorID AncestorLastName  Level  LevelDiff 
----------- -------------------- ----------- -------------------- ----------- ----------- 
1   Davis    NULL  NULL     0   NULL 
2   Funk     1   Davis    1   1 
3   Lew     2   Funk     2   1 
3   Lew     1   Davis    2   2 
4   Peled    3   Lew     3   1 
4   Peled    2   Funk     3   2 
4   Peled    1   Davis    3   3 
5   Buck     2   Funk     2   1 
5   Buck     1   Davis    2   2 
6   Suurs    5   Buck     3   1 
6   Suurs    2   Funk     3   2 
6   Suurs    1   Davis    3   3 
7   King     5   Buck     3   1 
7   King     2   Funk     3   2 
7   King     1   Davis    3   3 
8   Cameron    3   Lew     3   1 
8   Cameron    2   Funk     3   2 
8   Cameron    1   Davis    3   3 
9   Dolgopyatova   5   Buck     3   1 
9   Dolgopyatova   2   Funk     3   2 
9   Dolgopyatova   1   Davis    3   3 
+0

지금은 레벨 차이로 어떤 의미인지 알 수 있습니다. 작동하도록 할 수 있는지 알려주세요 ... –

+0

모두 표시하도록 업데이트했습니다. 나무에있는 멤버들 + 매 레벨마다 당신이 묻는대로 조상에 들어갔다. –

+0

거의 완벽하다. 그러나 결과 데이비스 - 데이비스는 정확하지 않습니다 (데이비스는 자신의 조상이 아닙니다). 마지막으로 선택하려면 'WHERE RCTE.CurEmpId! = RAnecestors.CurEmpId'를 추가해야하며 올바른 출력을 반환합니다. –

1

SQL에서는이 작업을 수행하지 않습니다. SQL 만 사용하여 조상이있는 사용자 목록을 얻는 것은 쉽지만, tree 구조가없는 상태에서 레벨 차이를 계산하는 방법을 잘 모르겠습니다. 나는 당신이 SQL을 가지고 그것을 할 수 없다는 것을 말하는 것이 아니며, 나는 머리 꼭대기에서 해결책을 모른다.

나는 사용자를 트리 데이터 구조에 넣을 것이다. 거기에서 레벨 차 (하위 트리의 높이)를 얻는 것이 더 쉬울 것입니다.

+0

하지만 빠른 쿼리와 절차를 빠르게 수행하려면이 목록이 필요합니다 –

관련 문제