В SQL Server, как я могу выбрать все записи в рекурсивной таблице? - PullRequest
3 голосов
/ 29 мая 2009

У меня есть рекурсивная таблица, в которой у каждой записи есть ID и PARENTID. PARENTID указывает на другой идентификатор в той же таблице. Есть ли способ в 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?

Ответы [ 6 ]

3 голосов
/ 29 мая 2009

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

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

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

2 голосов
/ 29 мая 2009

Вы можете использовать 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 
0 голосов
/ 29 мая 2009
0 голосов
/ 29 мая 2009

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

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

0 голосов
/ 29 мая 2009

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

Если вы можете (или для дальнейшего использования), вы можете попытаться использовать измененный обход дерева предзаказа , что позволит вам сделать это.

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

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

В статье, на которую я ссылался, я нашел отличное объяснение MPTT.

0 голосов
/ 29 мая 2009

id также имел эту проблему, но я не нашел решения. поэтому я создал этот обходной путь: я добавил новый столбец 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 * from tree_table where tree_id = 1;

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...