【问题标题】:In SQL Server, how can I select all records in a recursive table?在 SQL Server 中,如何选择递归表中的所有记录?
【发布时间】:2009-05-29 13:43:05
【问题描述】:

我有一个递归表,其中每条记录都有一个 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 等价物是什么?

【问题讨论】:

    标签: sql-server


    【解决方案1】:

    这是我为您整理的一个示例。它演示了如何使用递归公用表表达式 (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

    【讨论】:

    • 这对我有用,但我必须说这是一种非常迟钝的方式来做这种事情。
    • @JosephStyons:查看帖子的编辑以了解有关使用 SQL Server 2008 的替代方法的详细信息
    • @John Sansom:绝对错误,这绝对不等同,您错过了 nocycle 关键字。一旦有循环引用,您的变体就会爆炸。 AFAIK,在 SQL Server 中无法使用 nocycle...
    【解决方案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 
    

    【讨论】:

      【解决方案3】:

      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;
      

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

      希望这会有所帮助..

      【讨论】:

        【解决方案4】:

        我认为如果不在语句中使用递归,你就无法摆脱它。

        如果可以(或供将来参考),您可以尝试使用modified preorder tree traversal,这将允许您这样做。

        在此答案中解释修改后的预排序树遍历超出了范围,因为需要一些解释和游戏才能掌握。

        我会指出,在 MPTT 上更新和插入记录会产生开销,但选择通常要高效得多。一般来说,选择比更新/插入发生的要多得多,所以这是值得的,但是在直接进入之前考虑一下你的具体情况是值得的。

        我链接到的文章对 MPTT 进行了很好的解释。

        【讨论】:

          【解决方案5】:

          您应该能够使用公用表表达式进行递归查询。谷歌搜索“Recursive Queries Using Common Table Expressions”,有一篇msdn文章。

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-11
            • 2018-07-05
            相关资源
            最近更新 更多