2012-01-27 63 views
3

我有用戶列表。每個用戶都有一個由字段ParentId定義的層次結構(很少用戶位於層次結構之上 - 它們在此字段中爲空)。我不想改變這個表的結構(並且添加了exaple hierarchyId到表)。如何從層次結構中獲取所有用戶關係的列表?

在這一刻,我有這個表:
用戶:

UserId INT NOT NULL, ManagerId INT NULL, other fields 

我需要創建的所有關係的列表形式的用戶之間的用戶祖先和水平的差異:

UserId, AncestorId, LevelDifference 

示例:
來自用戶表:
UserId INT NOT NULL,ManagerId INT NULL
1,NULL,(吉姆)
2,1(喬什)
3,2(珍妮)

我應該得到:
用戶ID,AncestorId,LevelDifference
2,1,1
3, 2,1
3,1,2 - (吉姆是珍妮的祖先之一)

有沒有人有一些想法如何以快速的方式做到這一點?

+1

什麼版本的SQL Server? 2005+可爲您提供[遞歸CTE](http://msdn.microsoft.com/zh-cn/library/ms186243.aspx)。 – 2012-01-27 21:55:34

+0

對不起,我忘了版本,它是2008年 - 我用cte檢查是否有人在祖先線上,但檢查所有用戶之間的關係非常緩慢,應該有辦法從另一側做 – 2012-01-27 22:01:46

+0

建立並返回內存表的T-SQL函數是否可行? – 2012-01-27 22:21:44

回答

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 

輸出:

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

我看你的水平差,現在的意思,讓我看看,如果我能得到它的工作... – 2012-01-28 00:22:57

+0

我已經更新,以顯示所有在樹+在那裏ancestory每一個級別的成員,你問 – 2012-01-28 01:18:08

+0

近乎完美。但是結果戴維斯 - 戴維斯是不正確的(戴維斯不是他自己的祖先)。你必須添加「WHERE RCTE.CurEmpId!= RAnecestors.CurEmpId」到最後一個選擇,然後它會返回正確的輸出。 – 2012-01-29 18:23:09

1

我不會在SQL中這樣做。很容易得到一個只使用sql的祖先用戶列表,但我不知道如何在沒有tree結構的情況下計算leveldifference。我並不是說你不能用sql來完成,我只是不知道解決方案在我頭頂。

我會把你的用戶變成一個樹形數據結構。從那裏可以更容易地獲得級別差異(子樹的高度)。

+0

,但我需要這個名單,以做出更快一些查詢和過程 – 2012-01-27 22:03:15

相關問題