Иерархия дерева SQL Server и вложенные наборы с дублирующими идентификаторами записей - PullRequest
3 голосов
/ 14 июля 2009

Учитывая, что у меня есть эта структура набора результатов (лишние поля были удалены)

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

возможно ли вернуть записи в древовидном порядке, то есть Parent, затем Children, если Child - это Parent, то их 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 */

Единственный способ, которым я могу думать об этом, - это следовать этой статье -

Улучшение производительности иерархии с помощью вложенных наборов

и включите поля [LeftExtent] и [RightExtent] для каждой записи. Теперь SQL в статье работает нормально, когда Ids уникальны, но в этой конкретной древовидной структуре запись с одинаковым 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], или я полностью упускаю более простой способ вернуть набор результатов в требуемом порядке?

Ответы [ 3 ]

7 голосов
/ 14 июля 2009

Вот тот, который помогает мне:

@ ParentID - это только отправная точка в иерархии, но вы можете передать 0 (но я думаю, что вы используете null в качестве базового идентификатора, так что вы поймете)

Ключом к упорядоченной сортировке является созданный ключ сортировки.

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
3 голосов
/ 14 июля 2009

Вы должны взглянуть на рекурсивные общие табличные выражения в 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

Это должно дать вам хороший набор результатов запроса с данными, которые вы ищете. Или я что-то упустил?

Марк

0 голосов
/ 14 июля 2009

Если бы вы использовали материализованный путь или ИЕРАРХИИД , ваша жизнь была бы намного проще ...

...