Рекурсивный выбор в SQL - PullRequest
       74

Рекурсивный выбор в SQL

9 голосов
/ 13 апреля 2011

У меня проблема, я просто не могу разобраться. Я знаю, чего хочу, просто не могу вывести это на экран. У меня есть таблица, похожая на эту:

Id, PK UniqueIdentifier, NotNull
Name, nvarchar(255), NotNull
ParentId, UniqueIdentifier, Null

У ParentId есть FK-Id.

Что я хочу сделать, это получить список всех идентификаторов ниже идентификатора, который я передаю.

пример:

1   TestName1    NULL
2   TestName2    1
3   TestName3    2
4   TestName4    NULL
5   TestName5    1

Дерево будет выглядеть так:

-1
  -> -2
       -> -3
  -> -5
-4

Если бы я сейчас попросил 4, я бы вернул только 4, но если бы я попросил 1, я бы получил 1, 2, 3 и 5. Если бы я попросил 2, я бы получил 2 и 3 и т. Д.

Есть ли кто-нибудь, кто может указать мне правильное направление. Мой мозг зажарен, поэтому я ценю любую помощь, которую могу получить.

Ответы [ 5 ]

15 голосов
/ 13 апреля 2011
declare @T table(
  Id int primary key,
  Name nvarchar(255) not null,
  ParentId int)

insert into @T values
(1,   'TestName1',    NULL),
(2,   'TestName2',    1),
(3,   'TestName3',    2),
(4,   'TestName4',    NULL),
(5,   'TestName5',    1)

declare @Id int = 1

;with cte as
(  
  select T.*
  from @T as T
  where T.Id = @Id
  union all
  select T.*
  from @T as T
    inner join cte as C
      on T.ParentId = C.Id
)
select *
from cte      

Результат

Id          Name                 ParentId
----------- -------------------- -----------
1           TestName1            NULL
2           TestName2            1
5           TestName5            1
3           TestName3            2
4 голосов
/ 13 апреля 2011

Вот рабочий пример:

declare @t table (id int, name nvarchar(255), ParentID int)

insert @t values
(1,   'TestName1',    NULL),
(2,   'TestName2',    1   ),
(3,   'TestName3',    2   ),
(4,   'TestName4',    NULL),
(5,   'TestName5',    1   );

; with rec as
        (
        select  t.name
        ,       t.id as baseid
        ,       t.id
        ,       t.parentid
        from    @t t
        union all
        select  t.name
        ,       r.baseid
        ,       t.id
        ,       t.parentid
        from    rec r
        join    @t t
        on      t.ParentID = r.id
        )
select  *
from    rec
where   baseid = 1

Вы можете фильтровать по baseid, который содержит начало дерева, к которому вы обращаетесь.

0 голосов
/ 13 апреля 2011

Я предполагаю, что самый простой способ выполнить то, что вы ищете, - это написать рекурсивный запрос, используя выражение общей таблицы:

MSDN - Рекурсивные запросы с использованием выражений общих таблиц

0 голосов
/ 13 апреля 2011

Попробуйте это:

WITH RecQry AS
(
    SELECT *
      FROM MyTable
    UNION ALL
    SELECT a.*
      FROM MyTable a INNER JOIN RecQry b
        ON a.ParentID = b.Id
)
SELECT *
  FROM RecQry
0 голосов
/ 13 апреля 2011

Вот хорошая статья о ИД модели иерархии . Он идет от самого начала данных до дизайна запросов.

Кроме того, вы можете использовать рекурсивный запрос, используя общее табличное выражение .

...