在SQL Server中,如何选择递归表中的所有记录?

时间:2009-05-29 13:43:05

标签: sql-server

我有一个递归表,其中每个记录都有一个ID和一个PARENTID。 PARENTID指向同一个表中的不同ID。 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 个答案:

答案 0 :(得分: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

编辑另外,在SQL Server 2008中,有一种名为hierarchyid的数据类型可用于实现分层数据结构。请参阅以下教程

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

答案 1 :(得分:2)

您可以像这样使用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 

答案 2 :(得分:0)

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语句从树中获取所有节点。

select * from tree_table where tree_id = 1;

但也可能有一些存储过程可以帮助您解决问题。

希望这会有所帮助..

答案 3 :(得分:0)

我不认为你可以在你的陈述中不使用递归而逃脱它。

如果您能够(或将来参考),您可以尝试使用modified preorder tree traversal,这样您就可以执行此操作。

在这个答案中解释修改后的预订树遍历超出了范围,因为它需要一些解释和播放才能掌握。

我将指出MPTT上有更新和插入记录的开销,但选择通常效率更高。一般来说,选择比更新/插入要多得多,所以值得,但在直接进入潜水之前考虑一下你的特殊情况是值得的。

我与之相关的文章我找到了对MPTT的一个很好的解释。

答案 4 :(得分:0)

您应该能够使用公用表表达式来执行递归查询。在谷歌搜索“使用公用表表达式的递归查询”,有一篇msdn文章。

叹息不允许新用户添加超链接。

答案 5 :(得分:0)