SQL Server树层次结构和具有重复记录ID的嵌套集

时间:2009-07-14 10:56:57

标签: sql sql-server sql-server-2005 tree nested-sets

鉴于我有这个结果集结构(多余的字段已被剥离)

Id | ParentId | Name | Depth
----------------------------

是否可以按树顺序返回记录,即Parent然后Children,如果ChildParent,那么他们的Children,如果不是那么Sibling等?例如,

Id | ParentId | Name | Depth
----------------------------
1    NULL       Major    1
2    1          Minor    2
3    1          Minor    2
4    3          Build    3
5    3          Build    3
6    1          Minor    2

/* etc, etc */

我能想到这样做的唯一方法就是遵循这篇文章 -

Improve hierarchy performance using nested sets

并在每条记录中加入[LeftExtent][RightExtent]字段。现在,当Ids是唯一的时,文章中的SQL工作正常,但在这个特定的树结构中,具有相同Id的记录可以出现在树中的不同位置(ParentId字段显然是不同的。我认为问题出在本文的SQL中 -

  INSERT INTO @tmpStack
    (
      EmployeeID, 
      LeftExtent
    )
  SELECT TOP 1 EmployeeID, @counter 
  FROM Employee 
  WHERE ISNULL(ParentID, 0) = ISNULL(@parentid,0) 
  /* If the Id has already been added then record is not given [LeftExtent] or [RightExtent] values. */
  AND EmployeeID NOT IN (SELECT EmployeeID FROM @tmpStack) 

如何更改以允许具有重复Ids的记录被赋予[LeftExtent]和[RightExtent]值,或者我完全错过了以我需要的顺序返回结果集的更简单方法? / p>

3 个答案:

答案 0 :(得分:7)

这是一个为我提供技巧的方法:

@ParentID只是层次结构中的起点,但你可以传入0(但我认为你使用null作为基本ID,所以你会得到这个想法)

有序排序的关键是使用已建立的排序键。

WITH RoleHierarchy (RoleID, [Role], [Description], ParentID, Editable, HierarchyLevel, SortKey) AS
(
   -- Base
   SELECT
        RoleID,
        [Role],
        [Description],
        ParentID,
        Editable,
        0 as HierarchyLevel,
        CAST(RoleID AS VARBINARY(300))
   FROM
        dbo.Roles       
   WHERE
        RoleID = @ParentID

   UNION ALL

   -- Recursive
   SELECT
        e.RoleID,
        e.[Role],
        e.[Description],
        e.ParentID,
        e.Editable,
        th.HierarchyLevel + 1 AS HierarchyLevel,
        CAST (th.SortKey + CAST (e.[Role] AS VARBINARY(100)) + CAST (e.[RoleID] AS VARBINARY(100)) AS VARBINARY(300))
   FROM
        Roles e
        INNER JOIN RoleHierarchy th ON e.ParentID = th.RoleID
    WHERE
        e.RoleID != 0
)

SELECT
    RoleID,
    ParentID,
    [Role],
    [Description],
    Editable,
    HierarchyLevel
FROM
    RoleHierarchy
WHERE
    RoleID != @ParentID
ORDER BY
    SortKey

答案 1 :(得分:3)

您应该查看SQL Server 2005中的递归公用表表达式:

在您的情况下,这将是:

WITH EmployeeCTE AS
(
   -- get the anchor
   SELECT ID, ParentID, Name, 0 as 'Depth'
   FROM Employee WHERE ParentID IS NULL

   -- recursively union lower levels
   UNION ALL
   SELECT e.ID, e.ParentID, e.Name, e.Depth+1
   FROM Employee e
   INNER JOIN EmployeeCTE ON e.ParentID = EmployeeCTE.ID
)
SELECT * FROM EmployeeCTE

这应该为您提供一个很好的查询结果集,其中包含您正在寻找的数据。或者我错过了什么?

马克

答案 2 :(得分:0)

如果您使用materialized pathHIERARCHYID,那么生活会更容易......