2012-01-27 64 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

相关问题