sql-server - 选择父行及其子行和孙子行
问题描述
我有一个评论表,我试图完成能够选择根评论(`ParentCommentId = 0)然后从我回来的父评论中选择我所有的孩子和那些孩子的孩子等等
例如,我会取回CommentId = 1038
. 我也想要它的孩子 ( CommentId = 1039
) 因为ParentCommentId = 1038
, 然后还CommentId = 1040
因为它是ParentCommentId = 1039
等等。
我尝试了以下查询,因为我认为我的方向是正确的。
SELECT *
FROM
(SELECT
c.CommentId,
c.PostId,
c.Comment,
c.ParentCommentId,
c.CommentDateTime
FROM
[gallery].[Comments] c
INNER JOIN
[player].[Players] p ON p.UserId = c.UserId
WHERE
c.PostId = 32
AND ParentCommentId = 0) AS ParentComments
JOIN
(SELECT
c.CommentId,
c.PostId,
c.Comment,
c.ParentCommentId,
c.CommentDateTime
FROM
[gallery].[Comments] c
INNER JOIN
[player].[Players] p ON p.UserId = c.UserId
WHERE
c.PostId = 32
AND ParentCommentId != 0) AS ChildComments ON ParentComments.CommentId = ChildComments.ParentCommentId
但我肯定会得到错误的数据,比如与父母在同一行的孩子,理想情况下我希望孩子们成为单独的行。它也只有 1 个孩子的深度,而且肯定缺少很多评论(比下图的 5 个要多得多)。我似乎只得到一个根评论,它是第一个孩子,而不是任何没有孩子的孩子或根评论大孩子。
解决方案
您可能会丢失数据,因为您使用了inner join
. 这对于祖父母不在表格中的情况是有问题的,例如:
- 因为
CommentID = 1036
我们没有在数据提取中给出祖父母/父母 - 对于层次结构级别 1 的任何评论(即 Parent = 0)
使用 aleft join
应该可以解决这个问题。
使用的数据
declare @target table (
CommentID int
,PostID int
,Comment varchar(200)
,ParentCommentId int
);
insert into @target
values
(1036, 32, 'Que?', 1033)
,(1037, 32, 'What up mane', 1035)
,(1038, 32, 'Hi', 0)
,(1039, 32, 'Can you see me?', 1038)
,(1040, 32, 'Test', 1039)
,(1041, 32, 'T', 1038)
,(1042, 32, 'Yoooo', 0)
,(1043, 32, 'Test?', 1042)
,(1044, 32, 'Test 1', 1039)
,(1045, 32, 'Test 2', 1039)
;
获取层次结构
可以构建一个简单的层次结构表,显示三个层次
select
GrandParentCommentID = isnull(b.ParentCommentID, 0)
,a.ParentCommentID
,a.CommentID
from @target as a
left join @target as b on a.ParentCommentId = b.CommentID
完整答案
with Hierarchy as (
select
GrandParentCommentID = b.CommentID
,a.ParentCommentID
,a.CommentID
from @target as a
inner join @target as b on a.ParentCommentId = b.CommentID
)
select
hier.GrandParentCommentID
,hier.ParentCommentID
,hier.CommentID
,details.Comment
from Hierarchy as hier
inner join @target as details on details.CommentID = hier.CommentID
order by
hier.GrandParentCommentID
,hier.ParentCommentID
结果
奖金
如果您想将级别作为一列,您可以使用递归 CTE,如下所示(我相信有更好的方法):
;with Hierarchy as (
select
GrandParentCommentID = 0
,ParentCommentID = 0
,CommentID
,hier_level = 1
from @target where ParentCommentID = 0
union all
select
GrandParentCommentID = h.ParentCommentID
,t.ParentCommentID
,t.CommentID
,hierarchy_level = h.hier_level + 1
from Hierarchy as h
inner join @target as t on t.ParentCommentId = h.CommentID
)
select * from Hierarchy
添加一个孙子进行演示:
insert into @target values (1045, 32, 'Test 2', 1039);
推荐阅读
- dynamics-crm - 我们在动态 CRM 中是否具有离线(移动/标签)中的服务协议许可 (SLA) 可行性?
- arrays - 如何在 api 中将 JSON 对象转换为 Typescript 数组
- jquery - 有效功能不起作用 需要帮助
- scala - Scala:带有 Quill 的 Oracle JDBC 泛型
- java - 使用wildfly在mysql中插入印地语文本时出现问题
- excel - 从一张纸复制数据并将其粘贴到另一张纸上
- smartcard - 我可以解锁我的 SLE4442 智能卡吗?PUK码是否存在?
- java - 如何避免将spring boot fat jar安装/部署到maven repo
- drupal - 禁用在联系表格 Drupal 7 中向发件人发送副本
- python - PSO 可以基于 ODE 的实验数据工作吗?