2011-12-27 19 views
1

我正在建立一個論壇。現在我想創建一個查詢,返回每個帖子上的反應次數。反應被定義爲某個帖子下的所有帖子。我想用CTE來實現這一點。如何使用通用表達式(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,我知道你可以做遞歸查詢,但我不知道如何解決創建遞歸查詢的問題。

+0

你可以添加你已經嘗試過的代碼(遞歸)嗎? MSDN CTE文檔對於遞歸CTE非常有用,所以它會更有用,可以幫助您瞭解哪裏出錯,而不僅僅是編寫您的代碼 – gbn 2011-12-27 10:04:18

+0

我也添加了我的失敗 – 2011-12-27 10:09:15

+0

其他例外我已經遇到的是:「外連接不允許在遞歸公用表表達式'反應'的遞歸部分。」和「語句終止,最大遞歸100在語句完成之前已經耗盡。」 – 2011-12-27 10:10:41

回答

2
  • 構建帖子列表第一
  • 總結後
  • 不需要離開了遞歸子句中JOIN
  • 需要爲下一級遞歸子句中得到PARENTID,否則你只是循環帖子ID在同一水平帖子ID

事情是這樣的:

;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 
+0

我想列出帖子。*與反應的數量作爲一個添加字段。我的一個領域是一個XML領域(正文),這就是爲什麼我第一次使用CTE(http://stackoverflow.com/questions/8616319/how-to-add-xml-data-type-in​​-a -group逐子句)。嗯...也許我需要在我的情況下創建兩個CTE。 – 2011-12-27 10:23:10

+0

如果我:';隨反應AS ( SELECT的ParentId FROM dbo.Post UNION ALL SELECT Reaction.ParentId FROM dbo.Post JOIN反應ON Reaction.ParentId = Post.PostId ),反應物作爲 ( \t SELECT COUNT(*)作爲CNT,的ParentId FROM反應GROUP BY的ParentId ) SELECT ISNULL(CNT,0),郵政。* FROM 郵政dbo.Post LEFT JOIN反應 ON Reactions.ParentId = Post.PostId ',我得到一個'聲明終止。在語句完成之前,最大遞歸100已經耗盡。例外。 – 2011-12-27 10:28:00

+0

更新的遞歸部分基於您的錯誤假設,即Reaction.ParentId。 **這個**問題是關於遞歸和計數的:你通常不會在同一查詢中混合「獲取數據」和*計數所有* – gbn 2011-12-27 10:33:00

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