按逻辑顺序排列论坛帖子

时间:2017-01-16 09:45:56

标签: sql .net sql-server tsql

我有三列

ThreadID
DateTime
CommentID
ReplyCommentID

查询

WITH CTE AS ( SELECT CommentID ,
            CommentUserName,
             ReplyCommentID ,
            CommentID AS ThreadID ,
            CAST( CommentID AS VARCHAR( MAX ) ) AS PathStr,
            HtmlComment ,
            CommentPostDocumentID ,
             CommentIsApproved,
            CommentDate 

     FROM Blog_CommentDetails AS T WITH(NOLOCK)
     WHERE ReplyCommentID IS NULL
     UNION ALL
     SELECT T.CommentID ,
            T.CommentUserName,
            T.ReplyCommentID ,
            CTE.ThreadID ,
            PathStr + '-'+ CAST( T.ReplyCommentID AS VARCHAR( MAX ) ) AS PathStr,
            T.HtmlComment ,
            t.CommentPostDocumentID ,
             t.CommentIsApproved,
            T.CommentDate 

     FROM Blog_CommentDetails AS T WITH(NOLOCK)
     JOIN CTE 
     ON T.ReplyCommentID = CTE.CommentID
     WHERE T.ReplyCommentID IS NOT NULL)

SELECT *
FROM CTE
WHERE CommentPostDocumentID = 15 AND CommentIsApproved=1
ORDER BY ThreadID, PathStr ,
        CommentDate DESC;

我需要先通过ThreadID升序排序 然后我需要按CommentID升序排序 然后我需要按日期降序排序第三 但有一个条件,当有两行的commenid和replycommendid匹配时,应该首先使用commenid行。

我如何为此编写订单?

ORDER BY  ThreadID,CommentID,DateTime desc,

IF(ReplyCommentID == CommentID) 
then 
rows with commentid should be first

目前的结果:

actual result 但预期的结果是:

expected result

2 个答案:

答案 0 :(得分:0)

您可以使用计算值进行排序;但是,由于计算需要来自单独行的属性,因此首先要组合这些行。 如果没有文本形式的演示数据,我可以接管我的环境,那么测试就有点难了。

如果我们认为a代表CommentIdb代表ReplyCommentID,则以下架构非常接近您的要求:

create table test (
    a int,
    b int
    );

insert into test (a,b) values (1,null), (2,1), (3,2), (4,1);

select distinct test.a as a, test.b as b, case when (test.b=test2.a or test.b is null) then 0 else 1 end as priority
from test left join test test2 on test.b = test2.a and test2.b is null
order by priority,a,b

请注意,与order by a,b相比的订单与您在样本数据中的预期类似。

Givent在申请查询时(在WITH CTE... - 部分之后),它应该如下所示。如上所述,我无法测试它,所以如果它不能立即起作用,请不要向我扔石头:

SELECT distinct cte.*, case when (cte.ReplyCommentID =cte2.CommentId or cte.ReplyCommentID is null) then 0 else 1 end as priority
FROM CTE left join CTE cte2 on cte.ReplyCommentID = cte2.CommentId and cte2.ReplyCommentID is null
WHERE CommentPostDocumentID = 15 AND CommentIsApproved=1
ORDER BY ThreadID, priority, CommentId, PathStr , CommentDate DESC;

Result

答案 1 :(得分:0)

以下大量示例将介绍基于CommentIDReplyCommentID(用作ParentID)的评论树。同一ReplyCommentID的孩子按CommentDate DESC排序:

DECLARE @Table TABLE (
    CommentID INT,
    ReplyCommentID INT,
    CommentDate DATETIME
);

INSERT INTO @Table VALUES
(140,NULL, CAST('20170109' AS DATETIME))
,(141,NULL, CAST('20170110' AS DATETIME))
,(142,141, CAST('20170111' AS DATETIME))
,(143,141, CAST('20170112' AS DATETIME))
,(144,141, CAST('20170113' AS DATETIME))
,(145,144, CAST('20170114' AS DATETIME))
,(146,NULL, CAST('20170115' AS DATETIME));

WITH [Statistics] AS (
    SELECT Records.CommentID, Records.ReplyCommentID
    , COUNT(Children.CommentID) AS NrOfChildren
    , ROW_NUMBER() OVER (PARTITION BY Records.ReplyCommentID ORDER BY Records.CommentDate DESC) AS NthChild
    , COUNT(Records.CommentID) OVER (PARTITION BY Records.ReplyCommentID) AS NrOfSiblings
    FROM @Table Records
    LEFT JOIN @Table Children ON Records.CommentID = Children.ReplyCommentID
    GROUP BY Records.CommentID, Records.ReplyCommentID, Records.CommentDate
)

, Tree AS (
    SELECT *
    , 1 AS [Order]
    , 0 AS [Rerouting]
    , CAST(-1 AS INT) AS ReroutedFromNthChild
    FROM [Statistics] AS TreeNode 
    WHERE ReplyCommentID IS NULL AND NthChild = 1

    UNION ALL

    SELECT NextNode.*
    , TreeNode.[Order] + 1 AS [Order]
    , CASE 
        WHEN (TreeNode.NrOfChildren = 0 AND TreeNode.NthChild = TreeNode.NrOfSiblings AND TreeNode.ReplyCommentID = NextNode.CommentID)
        OR (TreeNode.Rerouting = 1 AND TreeNode.ReroutedFromNthChild = TreeNode.NrOfChildren AND TreeNode.ReplyCommentID = NextNode.CommentID) 
            THEN 1
        ELSE 0
        END AS [Rerouting]
    , CAST(TreeNode.NthChild AS INT) AS ReroutedFromNthChild
    FROM Tree AS TreeNode
    JOIN [Statistics] AS NextNode 
        --Has children, so select first child
        ON (TreeNode.Rerouting = 0 AND TreeNode.NrOfChildren > 0 AND NextNode.NthChild = 1 AND TreeNode.CommentID = NextNode.ReplyCommentID) 
        --Has no children, so select next sibling
        OR (TreeNode.Rerouting = 0 AND TreeNode.NrOfChildren = 0 AND TreeNode.NthChild + 1 = NextNode.NthChild AND (TreeNode.ReplyCommentID = NextNode.ReplyCommentID OR (TreeNode.ReplyCommentID IS NULL AND NextNode.ReplyCommentID IS NULL)))
        --Has no children or following siblings, so retrace the step (reroute)
        OR (TreeNode.Rerouting = 0 AND TreeNode.NrOfChildren = 0 AND TreeNode.NthChild = TreeNode.NrOfSiblings AND TreeNode.ReplyCommentID = NextNode.CommentID)
        --Was rerouting but has children, so back on track and follow the next child
        OR (TreeNode.Rerouting = 1 AND TreeNode.ReroutedFromNthChild < TreeNode.NrOfChildren AND TreeNode.ReroutedFromNthChild + 1 = NextNode.NthChild AND TreeNode.CommentID = NextNode.ReplyCommentID)
        --Was rerouting and has no other children, so continue rerouting
        OR (TreeNode.Rerouting = 1 AND TreeNode.ReroutedFromNthChild = TreeNode.NrOfChildren AND TreeNode.ReplyCommentID = NextNode.CommentID)
        --Rerouted to the top without children left, jumping to the next sibling
        OR (TreeNode.Rerouting = 1 AND (TreeNode.ReroutedFromNthChild = TreeNode.NrOfChildren OR TreeNode.NrOfChildren = 0) AND TreeNode.NthChild + 1 = NextNode.NthChild AND TreeNode.ReplyCommentID IS NULL AND NextNode.ReplyCommentID IS NULL)
)

select *
from Tree
where Rerouting = 0
ORDER BY [Order]

Result