2009-05-29 37 views
3

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

编辑:作为一个额外的想法,在SQL Server 2008中有一个数据类型,称为HIERARCHYID可用于实现分层数据结构。请参见下面的教程

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

+0

这为我工作,但我必须说,这是做这种事情相当钝的方式。 – JosephStyons 2009-05-29 15:40:54

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

您应该可以使用公用表表达式来执行递归查询。做一个谷歌搜索“递归查询使用通用表表达式”,有一个MSDN文章。

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

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 
相关问题