为递归CTE获取1个以上的结果集?

时间:2013-08-03 16:46:15

标签: sql-server common-table-expression

我有一个简单的表,其中包含叶子和子叶信息。 (比如论坛问题)

定义消息,其中childIdParentID相同

enter image description here

所以我们在这里看到2个主要问题及其答案。

我还设法计算每个元素的深度:

enter image description here

简而言之,这是主要问题:

    WITH CTE AS
    (
       SELECT childID
             ,parentID,
             0 AS depth,name
       FROM   @myTable
       WHERE   childID = parentID AND childID=1 -- problem line

       UNION ALL

       SELECT TBL.childID
             ,TBL.parentID,
              CTE.depth + 1 , TBL.name 
       FROM   @myTable AS TBL
               INNER JOIN CTE  ON  TBL.parentID = CTE.childID
       WHERE   TBL.childID<>TBL.parentID
    )
    SELECT childID,parentID,REPLICATE('----', depth) + name        

但问题是第8行(评论)。

我目前要求“向我提供问题ID#1的所有群集”

问题出在哪里?

我想为每个问题设置多个结果集!

所以这里我需要有2个结果集:

childId=parentId=1一个 和一个 一个childId=parentId=6

full working sql online

(我不想使用光标)

4 个答案:

答案 0 :(得分:9)

您可以动态构建查询。

DECLARE @SQL NVARCHAR(MAX) =
(SELECT '
WITH CTE AS
(
   SELECT childID
         ,parentID,
         0 AS depth,name
   FROM   myTable
   WHERE   childID = parentID AND childID = '+CAST(childID AS NVARCHAR(10))+'

   UNION ALL

   SELECT TBL.childID
         ,TBL.parentID,
          CTE.depth + 1 , TBL.name 
   FROM   myTable AS TBL
           INNER JOIN CTE  ON  TBL.parentID = CTE.childID
   WHERE   TBL.childID<>TBL.parentID
)
SELECT childID,parentID,REPLICATE(''----'', depth) + name
FROM   CTE   
ORDER BY
      childID;'

FROM  myTable
WHERE childID = parentID
FOR XML PATH(''), TYPE).value('text()[1]', 'NVARCHAR(MAX)');

EXEC sp_executesql @SQL;

更新

正如Bogdan Sahlean所建议的,我们可以通过参数化实际查询来最小化编译。

DECLARE @SQL1 NVARCHAR(MAX) =
'WITH CTE AS
(
   SELECT childID
         ,parentID,
         0 AS depth,name
   FROM   myTable
   WHERE   childID = parentID AND childID = @childID

   UNION ALL

   SELECT TBL.childID
         ,TBL.parentID,
          CTE.depth + 1 , TBL.name 
   FROM   myTable AS TBL
           INNER JOIN CTE  ON  TBL.parentID = CTE.childID
   WHERE   TBL.childID<>TBL.parentID
)
SELECT childID,parentID,REPLICATE(''----'', depth) + name
FROM   CTE   
ORDER BY
      childID;'

DECLARE @SQL2 NVARCHAR(MAX) =
(SELECT 'exec sp_executesql @SQL, N''@childID int'', '+CAST(childID AS NVARCHAR(10))+';'
FROM  myTable
WHERE childID = parentID
FOR XML PATH(''), TYPE).value('text()[1]', 'NVARCHAR(MAX)');

EXEC sp_executesql @SQL2, N'@SQL NVARCHAR(MAX)', @SQL1;

答案 1 :(得分:8)

要向客户端呈现多个结果集,您将不得不使用游标或while循环来执行独立的SELECT操作。您无法从CTE执行此操作,因为CTE只能由一个后续查询使用。

现在,问题的根源与游标无关,但事实上你正在使用HTML转发器。为什么需要为此使用HTML转发器?一个简单的DataReader可以循环遍历CTE的单集的所有结果,并根据循环做出条件格式化决策,并确定根ID的变化。因此,我建议您尝试以不同的方式解决表示问题,而不是试图强制SQL Server来适应您的表示实现。

答案 2 :(得分:0)

我不确定你的意思是“返回两个结果集”。你可以只有一个结果集,根问题被分配到另一个列吗?以下对您的查询进行了调整:

WITH CTE AS (
      SELECT ChildId as WhichQuestion, childID, parentID, 0 AS depth, name
      FROM   @myTable
      WHERE   childID = parentID
      UNION ALL
      SELECT cte.WhichQuestion, TBL.childID, TBL.parentID, CTE.depth + 1 , TBL.name 
      FROM   @myTable AS TBL
            INNER JOIN CTE  ON  TBL.parentID = CTE.childID
      WHERE   TBL.childID <> TBL.parentID
    )
SELECT WhichQuestion, childID, parentID, REPLICATE('----', depth) + name     
FROM   CTE   
ORDER BY WhichQuestion, childID;

答案 3 :(得分:-2)

您可以在root问题的锚点部分childId中保存,然后按需要的ID访问所有分支:

WITH CTE AS (
    SELECT childID as RootId
        , childID
        , parentID
        , 0 AS depth,name
    FROM @myTable
    WHERE childID = parentID
    UNION ALL
    SELECT CTE.RootId
        , TBL.childID
        , TBL.parentID
        , CTE.depth + 1 , TBL.name 
    FROM @myTable AS TBL
    INNER JOIN CTE  ON  TBL.parentID = CTE.childID
    WHERE TBL.childID<>TBL.parentID
)