如何使用公用表表达式(CTE)创建递归计数器?

时间:2011-12-27 09:59:25

标签: sql sql-server sql-server-2005 tsql

我正在建立一个论坛。现在我想创建一个返回每个帖子上的反应数量的查询。反应被定义为某个职位下的所有职位。我想用CTE来实现这一点。

我已经得到了这个票价:

;WITH Reaction(Cnt, ParentId) AS 
(
    SELECT  COUNT(*), ParentId
    FROM   dbo.Post
    GROUP  BY ParentId
)

SELECT ISNULL(Cnt, 0), Post.*
FROM   dbo.Post Post
       LEFT JOIN Reaction
         ON Reaction.ParentId = Post.PostId 

这是列出所有'直接'帖子。现在我必须让这个查询计算整个树,但我被卡住了。我一直在读CTE,我知道你可以进行递归查询,但我不知道如何解决创建递归查询的问题。

2 个答案:

答案 0 :(得分:2)

  • 首先构建帖子列表
  • 稍后聚合
  • 在递归条款中不需要LEFT JOIN
  • 需要在下一级别的recursive子句中获取ParentID,否则只需将PostId循环到同一级别的PostID

这样的事情:

;WITH Reaction AS 
(
    SELECT ParentId
    FROM dbo.Post
    UNION ALL 
    SELECT P.ParentId
    FROM dbo.Post P JOIN Reaction R ON R.ParentId = P.PostId
)
SELECT COUNT(*), ParentId FROM Reaction GROUP BY ParentId;

编辑,使用内嵌计数更新

;WITH Reaction AS
(
   SELECT ParentId FROM dbo.Post 
   UNION ALL 
   SELECT P.ParentId FROM dbo.Post P JOIN Reaction R ON R.ParentId = P.PostId
)
SELECT 
     COUNT(*) OVER (PARTITION BY Reactions.ParentId) AS Cnt,
     * 
FROM Post LEFT JOIN Reaction ON Reaction.ParentId = Post.PostId

答案 1 :(得分:0)

我最终使用双CTE来实现计数(基于@gbn的答案)。我需要这个,因为我有一个XML field that needed to be listed所以我无法使用GROUP BY

;WITH Reaction AS 
(
    SELECT ParentId
    FROM dbo.Post
    WHERE ParentId IS NOT NULL
    UNION ALL 
    SELECT P.ParentId
    FROM dbo.Post P JOIN Reaction R ON R.ParentId = P.PostId
    WHERE P.ParentId IS NOT NULL
), 
Reactions AS
(
    SELECT COUNT(*) as CNT, ParentId 
    FROM Reaction 
    GROUP BY ParentId
)

SELECT ISNULL(Reactions.CNT, 0), * 
FROM Post LEFT JOIN Reactions 
    ON Reactions.ParentId = Post.PostId