【问题标题】:How to show hierarchy row like parent child using SQL query如何使用 SQL 查询显示像父子一样的层次结构行
【发布时间】:2016-11-12 12:59:38
【问题描述】:

我在我的应用程序中使用博客 cmets,我在一个表中插入每个评论行,因此如果他们中的任何一个回复点击 commentid 的特定评论,我将在新行中插入 replyid

以下是屏幕截图:

在这里你可以看到commentid 24 和 26 有replycommentid 23。 我需要一个查询来在 23 之后显示 24 和 26。因为 23 是 24 和 26 的父级。

这是表格布局和示例数据的设置脚本:

USE [myDB]
GO
/****** Object:  Table [dbo].[Blog_CommentDetails]    Script Date: 11/12/2016 6:36:04 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Blog_CommentDetails](
    [CommentID] [int] IDENTITY(1,1) NOT NULL,
    [CommentUserName] [nvarchar](200) NOT NULL,
    [CommentText] [nvarchar](max) NULL,
    [CommentApprovedByUserID] [int] NULL,
    [CommentPostDocumentID] [int] NOT NULL,
    [CommentDate] [datetime] NULL DEFAULT (getdate()),
    [HtmlComment] [nvarchar](max) NULL,
    [CommentIsSpam] [bit] NULL CONSTRAINT [DEFAULT_Blog_MainComment_CommentIsSpam]  DEFAULT ((0)),
    [CommentIsApproved] [bit] NULL CONSTRAINT [DEFAULT_Blog_MainComment_CommentIsApproved]  DEFAULT ((0)),
    [CommentEmail] [nvarchar](250) NULL,
    [CommentInfo] [nvarchar](max) NULL,
    [ReplyCommentID] [int] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO
SET IDENTITY_INSERT [dbo].[Blog_CommentDetails] ON 

GO
INSERT [dbo].[Blog_CommentDetails] ([CommentID], [CommentUserName], [CommentText], [CommentApprovedByUserID], [CommentPostDocumentID], [CommentDate], [HtmlComment], [CommentIsSpam], [CommentIsApproved], [CommentEmail], [CommentInfo], [ReplyCommentID]) VALUES (22, N'Vikash', N'This is main comment', NULL, 1, CAST(N'2016-11-12 17:36:25.637' AS DateTime), N'<div class="main-comment-section"><div class="row"><div class="col-xs-12"><div class="post-comment-section"><p id="pCommentorName"><span id="sCommentorName" class="blogcommentname">Vikash</span><span id="sBlogPostedDate">Nov12,2016 5:35PM</span></p><p class="comment-detail" id="pBlogCommentDetails">This is main comment</p><div class="comment-reply"><ul><li><img src="assets/svg/components/blog-detail/icon_reply.svg" alt="Reply comment icon"><a class="joinus-link" id="btnComment" href="#" target="_self">::blogdetailsReply</a></li></ul></div></div></div></div></div>', 0, 1, N'vikash.kr@sonata-software.com', NULL, NULL)
GO
INSERT [dbo].[Blog_CommentDetails] ([CommentID], [CommentUserName], [CommentText], [CommentApprovedByUserID], [CommentPostDocumentID], [CommentDate], [HtmlComment], [CommentIsSpam], [CommentIsApproved], [CommentEmail], [CommentInfo], [ReplyCommentID]) VALUES (23, N'Megha k', N'This is reply comment', NULL, 1, CAST(N'2016-11-12 17:39:04.250' AS DateTime), N'<div class="reply-comment-section"><div class="row"><div class="col-xs-12"><div class="post-comment-section"><p id="pBlogReplyCommentorName"><span id="sReplyCommentorName" class="blogcommentname">Megha k</span><span id="sBlogReplyCommentDate">Nov12,2016 5:38PM</span></p><p class="comment-detail" id="pBlogReplyCommentDetails">This is reply comment</p><div class="comment-reply"><ul><li><img class="contributors-list" src="assets/svg/components/blog-detail/icon_reply.svg" alt="Reply comment icon"><a class="joinus-link" id="btnCommentReply" href="#" target="_self">::blogdetailsReply</a></li></ul></div></div></div></div></div>', 0, 1, N'megha.k@sonata-software.com', NULL, NULL)
GO
INSERT [dbo].[Blog_CommentDetails] ([CommentID], [CommentUserName], [CommentText], [CommentApprovedByUserID], [CommentPostDocumentID], [CommentDate], [HtmlComment], [CommentIsSpam], [CommentIsApproved], [CommentEmail], [CommentInfo], [ReplyCommentID]) VALUES (24, N'Siddappa H', N'This is reply text.', NULL, 1, CAST(N'2016-11-12 17:39:58.847' AS DateTime), N'<div class="main-comment-section"><div class="row"><div class="col-xs-12"><div class="post-comment-section"><p id="pCommentorName"><span id="sCommentorName" class="blogcommentname">Siddappa H</span><span id="sBlogPostedDate">Nov12,2016 5:39PM</span></p><p class="comment-detail" id="pBlogCommentDetails">This is reply text.</p><div class="comment-reply"><ul><li><img src="assets/svg/components/blog-detail/icon_reply.svg" alt="Reply comment icon"><a class="joinus-link" id="btnComment" href="#" target="_self">::blogdetailsReply</a></li></ul></div></div></div></div></div>', 0, 1, N'siddappa.h@sonata-software.com', NULL, 23)
GO
INSERT [dbo].[Blog_CommentDetails] ([CommentID], [CommentUserName], [CommentText], [CommentApprovedByUserID], [CommentPostDocumentID], [CommentDate], [HtmlComment], [CommentIsSpam], [CommentIsApproved], [CommentEmail], [CommentInfo], [ReplyCommentID]) VALUES (25, N'Suresh P', N'This is reply comment', NULL, 1, CAST(N'2016-11-12 17:40:44.470' AS DateTime), N'<div class="reply-comment-section"><div class="row"><div class="col-xs-12"><div class="post-comment-section"><p id="pBlogReplyCommentorName"><span id="sReplyCommentorName" class="blogcommentname">Suresh P</span><span id="sBlogReplyCommentDate">Nov12,2016 5:40PM</span></p><p class="comment-detail" id="pBlogReplyCommentDetails">This is reply comment</p><div class="comment-reply"><ul><li><img class="contributors-list" src="assets/svg/components/blog-detail/icon_reply.svg" alt="Reply comment icon"><a class="joinus-link" id="btnCommentReply" href="#" target="_self">::blogdetailsReply</a></li></ul></div></div></div></div></div>', 0, 1, N'suresh.p@sonata-software.com', NULL, NULL)
GO
INSERT [dbo].[Blog_CommentDetails] ([CommentID], [CommentUserName], [CommentText], [CommentApprovedByUserID], [CommentPostDocumentID], [CommentDate], [HtmlComment], [CommentIsSpam], [CommentIsApproved], [CommentEmail], [CommentInfo], [ReplyCommentID]) VALUES (26, N'Vikash', N'This is reply text', NULL, 1, CAST(N'2016-11-12 17:41:44.673' AS DateTime), N'<div class="reply-comment-section"><div class="row"><div class="col-xs-12"><div class="post-comment-section"><p id="pBlogReplyCommentorName"><span id="sReplyCommentorName" class="blogcommentname">Vikash</span><span id="sBlogReplyCommentDate">Nov12,2016 5:40PM</span></p><p class="comment-detail" id="pBlogReplyCommentDetails">This is reply text</p><div class="comment-reply"><ul><li><img class="contributors-list" src="assets/svg/components/blog-detail/icon_reply.svg" alt="Reply comment icon"><a class="joinus-link" id="btnCommentReply" href="#" target="_self">::blogdetailsReply</a></li></ul></div></div></div></div></div>', 0, 1, N'vikash.kr@sonata-software.com', NULL, 23)
GO
SET IDENTITY_INSERT [dbo].[Blog_CommentDetails] OFF
GO

欢迎所有建议!

我还在下面添加了三个插入查询:

Valex,请将此查询插入“INSERT [dbo].[Blog_CommentDetails] ([CommentID], [CommentUserName], [CommentText], [CommentApprovedByUserID], [CommentPostDocumentID], [CommentDate], [HtmlComment] 的表中], [CommentIsSpam], [CommentIsApproved], [CommentEmail], [CommentInfo], [ReplyCommentID], [IsRejected]) 值 (58, N'Vicky', N'Test', 0, 1, CAST(N'2016- 12-02 11:51:07.270' AS DateTime), N'VickyDec2,2016 11:47AM

Test
    Reply
', 0, 1, N'vicky@gmail.com', NULL , 空值,0) 去 插入 [dbo].[Blog_CommentDetails]([CommentID]、[CommentUserName]、[CommentText]、[CommentApprovedByUserID]、[CommentPostDocumentID]、[CommentDate]、[HtmlComment]、[CommentIsSpam]、[CommentIsApproved]、[CommentEmail]、[ CommentInfo], [ReplyCommentID]) VALUES (61, N'Billu', N'This is comment test', 0, 1, CAST(N'2016-12-02 12:35:40.220' AS DateTime), N'BilluDec2 ,2016 12:34PMThis is comment test
    Reply
', 0, 1, N'billu@gmail.com', NULL, 58) 去 插入 [dbo].[Blog_CommentDetails]([CommentID]、[CommentUserName]、[CommentText]、[CommentApprovedByUserID]、[CommentPostDocumentID]、[CommentDate]、[HtmlComment]、[CommentIsSpam]、[CommentIsApproved]、[CommentEmail]、[ CommentInfo], [ReplyCommentID]) VALUES (62, N'Rakesh', N'This is rakesh test', 0, 1, CAST(N'2016-12-02 12:37:42.133' AS DateTime), N'RakeshDec2 ,2016 12:36PMThis is rakesh test
    Reply
', 0, 1, N'rakesh@gmail.com', NULL, 58)

我现在正在编辑我的问题。 请检查下面的屏幕截图:

我使用了下面的查询:

WITH CTE AS ( SELECT CommentID ,

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

                     t.CommentPostDocumentID ,
                     t.CommentIsApproved,
                     T.CommentDate ,
                     T.ReplyCommentID ,
                     T.CommentUserName,
                     CTE.ThreadID ,
                     PathStr + '-'+ CAST( T.ReplyCommentID AS VARCHAR( MAX ) ) AS PathStr
              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 = 18 AND CommentIsApproved=1
            ORDER BY ThreadID ,
                        PathStr ,
                        CommentDate DESC

下面是显示评论的图片:

下面是预期的结构:

  1. 维卡什评论
  2. Sid 在 vi​​kash 评论中得到回复。
  3. Megha 对 vikash 发表了评论,因此 megha 的评论高于父 Vikash 下的 Sid。
  4. QE 回复了 Megha 的评论,所以他应该比 Sid 高,但它在最后一排。

【问题讨论】:

  • 我也在为这个表格编辑和添加脚本。
  • 谁能回答我的问题,我还在等待我的回答。

标签: sql-server sql-server-2008 tsql


【解决方案1】:

如果你想要完整的层次结构,甚至是其中的一部分,使用正确的顺序

编辑 - 删除了 2008 年的 Concat()

Declare @Top  int = 23 --null             --<<  Sets top of Hier Try 23
Declare @Nest varchar(25) ='|-----'  --<<  Optional: Added for readability

;with cteP as (
      Select Seq  = cast(1000+Row_Number() over (Order by CommentID) as varchar(500))
            ,CommentID
            ,ReplyCommentID
            ,Lvl=1
      From   [dbo].[Blog_CommentDetails]
      Where  IsNull(@Top,-1) = case when @Top is null then isnull(ReplyCommentID,-1) else CommentID end
      Union  All
      Select Seq  = cast(p.Seq+'.'+cast(1000+Row_Number() over (Order by r.CommentID) as varchar(25)) as varchar(500))
            ,r.CommentID
            ,r.ReplyCommentID
            ,p.Lvl+1
      From   [dbo].[Blog_CommentDetails] r 
      Join   cteP p on r.ReplyCommentID = p.CommentID)
     ,cteR1 as (Select *,R1=Row_Number() over (Order By Seq) From cteP)
     ,cteR2 as (Select A.Seq,A.CommentID,R2=Max(B.R1) From cteR1 A Join cteR1 B on (B.Seq like A.Seq+'%') Group By A.Seq,A.CommentID )
Select A.R1  
      ,B.R2
      ,A.CommentID
      ,A.ReplyCommentID
      ,A.Lvl
      ,CommentText = Replicate(@Nest,A.Lvl-1) + C.CommentText
      -- Include any other fields from [dbo].[Blog_CommentDetails] alias C
 From cteR1 A 
 Join cteR2 B on A.CommentID=B.CommentID
 Join [dbo].[Blog_CommentDetails] C on A.CommentID=C.CommentID
 Order By A.R1

返回

如果@Top 设置为 23(例如),则返回

我应该补充一点,cteR2 不是必需的,但它确实表示范围和/或父级或叶级。

【讨论】:

    【解决方案2】:

    您应该使用递归 CTE。这里是改编from your later question

    WITH CTE AS
    (
       SELECT CommentID, CommentUserName, CommentText,CommentDate,ReplyCommentID,
              CommentID as ThreadID,
              CAST(CommentID as varchar(MAX)) as PathStr
       FROM Blog_CommentDetails as T 
       WHERE ReplyCommentID IS NULL
    
       UNION ALL
    
       SELECT T.CommentID, T.CommentUserName, t.CommentText,T.CommentDate,
              T.ReplyCommentID,
              CTE.ThreadID,
              PathStr+'-'
              +CAST(T.ReplyCommentID as varchar(MAX)) as PathStr
       FROM Blog_CommentDetails as T 
       JOIN CTE ON T.ReplyCommentID = CTE.CommentID
       WHERE T.ReplyCommentID IS NOT NULL
    )
    
    SELECT * FROM CTE ORDER BY ThreadID,PathStr,CommentID, CommentDate desc
    

    结果:

    ╔═══════════╦═════════════════╦═══════════════════════╦═════════════════════════╦════════════════╦══════════╦═════════╗
    ║ CommentID ║ CommentUserName ║      CommentText      ║       CommentDate       ║ ReplyCommentID ║ ThreadID ║ PathStr ║
    ╠═══════════╬═════════════════╬═══════════════════════╬═════════════════════════╬════════════════╬══════════╬═════════╣
    ║        22 ║ Vikash          ║ This is main comment  ║ 2016-11-12 17:36:25.637 ║ NULL           ║       22 ║ 22      ║
    ║        23 ║ Megha k         ║ This is reply comment ║ 2016-11-12 17:39:04.250 ║ NULL           ║       23 ║ 23      ║
    ║        24 ║ Siddappa H      ║ This is reply text.   ║ 2016-11-12 17:39:58.847 ║ 23             ║       23 ║ 23-23   ║
    ║        26 ║ Vikash          ║ This is reply text    ║ 2016-11-12 17:41:44.673 ║ 23             ║       23 ║ 23-23   ║
    ║        25 ║ Suresh P        ║ This is reply comment ║ 2016-11-12 17:40:44.470 ║ NULL           ║       25 ║ 25      ║
    ╚═══════════╩═════════════════╩═══════════════════════╩═════════════════════════╩════════════════╩══════════╩═════════╝
    

    【讨论】:

    • Valex,我在上面的这个问题中添加了三个新的插入查询,请插入。插入后你会发现三个用户名 vicky、billu 和 Suresh,所以这里 vicky 是 billu 和 Suresh 的父级。并且根据评论日期,suresh 是最后一个评论的人,所以 rakesh 应该高于 billu 但仍然在这里 billu 首先显示,而 rakesh 在您的查询中排名第二。
    • @Vikash 我添加了这 3 个插入(将 vicky 的 ReplyCommentID 更改为 NULL 而不是插入中的 0)。在同等级别上,根据最后一个ORDER BY ThreadID,PathStr,CommentID 进行排序。因此,如果 billu 和 Suresh 与他们使用CommentID 订购的水平相同,如果您想根据CommentDate 订购它们,那么在最后的订购中将 CommentID 转换为 CommentDate
    • No Valex、Rakesh 和 billu 不在同一级别上,首先 billu 对 vicky 回复发表评论,然后在最后 rakesh 发表评论,因此根据预期的系统,rakesh 评论将上升,而 billu 将下降维基。你明白我的意思吗?如果您有任何疑问,请询问我。
    • @vikash 我的意思是它们都在同一个 vicky 的帖子下,因此它们具有相同的计算路径,您可以按照我之前评论中的说明随意订购它们。
    • 这就是我需要的解决方案,如何按照最后评论的顺序排列它们?
    【解决方案3】:

    您可以像下面显示的 smippet 一样订购它:

    select coalesce(replycommentid, commentid) as sequence, ...
    order by sequence, ...
    

    父行将使用它自己的 id 作为序列。

    【讨论】:

      【解决方案4】:

      如果我了解您要查找的内容,您希望每条评论后跟其回复,然后是任何(非回复)评论。我想你想要的只是这样:

      select * from Blog_CommentDetails
      order by coalesce(ReplyCommentID, commentID), CommentID
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-01-08
        • 1970-01-01
        • 2020-02-23
        • 2018-01-21
        • 1970-01-01
        • 2020-06-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多