Иерархические запросы в SQL Server 2005

Вернувшись, когда я работал в магазине Oracle, я принял CONNECT_BY как должное. Теперь я застрял в работе с SQL Server 2005 и имею некоторые неприятные иерархии объектов. В частности, у нас есть таблица самореференций, где все дочерние записи имеют столбец с родительским идентификатором. В настоящее время у нас есть представление, которое отображает детей на уровни в иерархии и неприятный запрос, который делает тяжелый подъем, чтобы связать родителей со своими детьми. Хотя этот метод работает, он далеко не изящный и пахнет пятнами. Мне просто интересно, как другие люди извлекают иерархические данные из SQL Server 2005.

Ответ 1

Это создает типичную иерархическую таблицу и использует CTE для выбора структуры иерархии и создания пути для каждого элемента.

CREATE TABLE tblHierarchy (ID int, ParentID int NULL, Name varchar(128));

INSERT INTO tblHierarchy VALUES (1, NULL, '1');
INSERT INTO tblHierarchy VALUES (2, NULL, '2');
INSERT INTO tblHierarchy VALUES (3, NULL, '3');
INSERT INTO tblHierarchy VALUES (4, 1, '1.1');
INSERT INTO tblHierarchy VALUES (5, 1, '1.2');
INSERT INTO tblHierarchy VALUES (6, 4, '1.1.1');

WITH Parent AS
(
    SELECT
        ID,
        ParentID,
        Name AS Path
    FROM
        tblHierarchy
    WHERE
        ParentID IS NULL

    UNION ALL

    SELECT
        TH.ID,
        TH.ParentID,
        CONVERT(varchar(128), Parent.Path + '/' + TH.Name) AS Path
    FROM
        tblHierarchy TH
    INNER JOIN
        Parent
    ON
        Parent.ID = TH.ParentID
)
SELECT * FROM Parent

ВЫВОД:

ID  ParentID    Path
1   NULL        1
2   NULL        2
3   NULL        3
4   1       1/1.1
5   1       1/1.2
6   4       1/1.1/1.1.1

Ответ 3

Используя оба, я обнаружил, что CONNECT BY несколько более гибкий и более простой в использовании, чем CTE. Вопрос не отличается от того, который я ответил несколько недель назад. См. здесь для краткого сравнения CONNECT BY и CTE и здесь для примера запроса с использованием CTE.

Ответ 5

в SQL Server 2005 для этого можно использовать Common Table Expressions (CTE).

Ответ 6

Чтобы пересечь глубину иерархии сначала, а затем следующий уровень брата, CTE может использоваться:

declare @tempTable TABLE
(
    ORGUID int,
    ORGNAME nvarchar(100), 
    PARENTORGUID int,
    ORGPATH nvarchar(max)
)

;WITH RECORG(ORGuid, ORGNAME, PARENTORGUID, ORGPATH)
as
(
    select 
        org.UID,
        org.Name,
        org.ParentOrganizationUID,
        dbo.fGetOrganizationBreadcrumbs(org.UID)
    from Organization org
    where org.UID =1

    union all

    select 
        orgRec.UID,
        orgRec.Name,
        orgRec.ParentOrganizationUID,
        dbo.fGetOrganizationBreadcrumbs(orgRec.UID) 
    from Organization orgRec
    inner join RECORG recOrg on orgRec.ParentOrganizationUID = recOrg.ORGuid

)
insert into @tempTable(ORGUID, ORGNAME, PARENTORGUID,ORGPATH)

select ORGUID, ORGNAME, PARENTORGUID,ORGPATH 
from  RECORG rec 

select * 
from @tempTable where ORGUID in(select MIN(tt.ORGUID) 
                                from @tempTable tt 
                                group by tt.PARENTORGUID)