2009-05-29 2 views
3

У меня есть рекурсивная таблица, в которой каждая запись имеет идентификатор и PARENTID. PARENTID указывает на другой идентификатор в той же таблице. Есть ли способ в SQL Server выбрать полное «дерево» в одном выражении? Я мог бы написать рекурсивную функцию для перехода от родителя ко всем дочерним элементам, но мне хотелось бы сделать это в одном запросе.В SQL Server, как я могу выбрать все записи в рекурсивной таблице?

В Oracle, это будет выглядеть следующим образом:

select 
    id, 
    parentid, 
    nodename 
from 
    MY_SCHEMA.MY_TABLE 
    connect by nocycle prior parentid = id 
start with id = :starting_id_number 
order by 
    id 

Что бы эквивалент SQL Server?

ответ

3

Вот пример, который я собрал для вас. Он демонстрирует использование рекурсивного общего табличного выражения (CTE).

CREATE TABLE #tempTable 
(
    ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY, 
    parentID INT NULL 
) 

INSERT INTO #tempTable (parentID) VALUES (null) 
INSERT INTO #tempTable (parentID) VALUES (1) 
INSERT INTO #tempTable (parentID) VALUES (1) 
INSERT INTO #tempTable (parentID) VALUES (2) 
INSERT INTO #tempTable (parentID) VALUES (3) 
INSERT INTO #tempTable (parentID) VALUES (2) 
INSERT INTO #tempTable (parentID) VALUES (5) 


SELECT * FROM #tempTable; 

WITH RecursiveTable (ID, ParentID, Level) 
AS 
(
    --Anchor 
    SELECT tt.ID, 
      tt.ParentID, 
      0 AS Level 
    FROM #tempTable AS tt 
    WHERE parentID IS null 
    UNION ALL 
    --Recursive member definition 
    SELECT tt.ID, 
      tt.ParentID, 
      LEVEL + 1 
    FROM #tempTable AS tt 
     INNER JOIN RecursiveTable rt ON 
     tt.ParentID = rt.ID 
) 
SELECT * 
FROM RecursiveTable 

DROP TABLE #tempTable 

Edit: В качестве дополнительной мысли, в SQL Server 2008 есть тип данных, называемый `hierarchyid`, которые могут быть использованы для реализации иерархических структур данных.Смотрите следующий учебник

http://technet.microsoft.com/en-us/library/bb677213.aspx

+0

Это работало для меня, но я должен сказать, что это довольно тупой способ сделать такого рода вещи. – JosephStyons

+0

@JosephStyons: взгляните на Редактировать сообщение, чтобы узнать подробности об альтернативном подходе с использованием SQL Server 2008 –

+0

@ Джон Сансом: Абсолютно неправильно, это абсолютно не эквивалентно, вы пропустили ключевое слово nocycle. Ваш вариант взорвется, как только появится циклическая ссылка. AFAIK, ноцикл в SQL-сервере невозможен ... –

0

У меня также была эта проблема, но я не нашел решения. поэтому я создал это обходное решение: Я добавил новый столбец «tree_id», чтобы моя таблица выглядела так.

treeid|id|parentid|nodename 
1  |1 | null | rootOfTreeOne 
1  |2 | 1  | childOfRootOne 
1  |3 | 1  | secondChild 
2  |4 | null | rootOfSecondTree 
2  |5 | 4  | childofSecondTree 

и создано дерево в программе. преимущество состоит в том, что вы можете получить все узлы из дерева с помощью простого простого оператора select.

select * from tree_table where tree_id = 1; 

, но также есть некоторые хранимые процедуры, которые могут помочь вам решить вашу проблему.

надеюсь, что это помогает ..

0

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

Если вы в состоянии (или для справки в будущем), вы можете попробовать использовать modified preorder tree traversal, что позволит вам это сделать.

Объяснение измененного обхода дерева предварительного заказа в этом ответе выходит за рамки, потому что требуется некоторое объяснение и игра, чтобы справиться с этим.

Отмечу, что в MPTT есть накладные расходы для обновления и вставки записей, но выбор обычно значительно более эффективен. В целом, выбор происходит намного больше, чем обновления/вставки, поэтому он того стоит, но стоит подумать о вашей конкретной ситуации перед тем, как погрузиться прямо.

Статья, с которой я связан, я нахожу отличное объяснение MPTT.

0

Вы должны иметь возможность использовать общие выражения таблицы для рекурсивного запроса. Сделайте поиск Google в разделе «Рекурсивные запросы с использованием общих выражений таблицы», есть статья msdn.

sigh новым пользователям не разрешено добавлять гиперссылки.

1

Вы можете использовать CTE как это;

CREATE TABLE TestTable 
( 
    ID int primary key NOT NULL, 
    ParentID int 
) 

INSERT INTO TestTable VALUES (0, null) 
INSERT INTO TestTable VALUES (1, 0) 
INSERT INTO TestTable VALUES (2, 0) 
INSERT INTO TestTable VALUES (3, 1) 
INSERT INTO TestTable VALUES (4, 3) 


-- Get branch 
;WITH TreeRecCTE (ID, ParentID, IDPath) 
AS 
(
    SELECT ID, ParentID, CONVERT(varchar(max), ID) As IDPath 
     FROM TestTable 
     WHERE ParentID IS NULL 
    UNION ALL 
    SELECT 
      Child.ID, 
      Child.ParentID, 
      Parent.IDPath + '.' + CONVERT(varchar(100),Child.ID) As IDPath 
     FROM TestTable As Child INNER JOIN TreeRecCTE AS Parent ON Child.ParentID = Parent.ID 
) 
SELECT * FROM TreeRecCTE WHERE IDPath LIKE '%.1.%' ORDER BY ParentID ASC 


-- Get complete tree: 
;WITH TreeRecCTE (ID, ParentID, IDPath) 
AS 
(
    SELECT ID, ParentID, CONVERT(varchar(max), ID) As IDPath 
     FROM TestTable 
     WHERE ParentID IS NULL 
    UNION ALL 
    SELECT 
      Child.ID, 
      Child.ParentID, 
      Parent.IDPath + '.' + CONVERT(varchar(100),Child.ID) As IDPath 
     FROM TestTable As Child INNER JOIN TreeRecCTE AS Parent ON Child.ParentID = Parent.ID 
) 
SELECT * FROM TreeRecCTE ORDER BY ParentID ASC 
Смежные вопросы