SQL Server中获取特定父记录的全部子级链

3
我们希望根据SQL Server中的ID获取特定记录的完整TREE结构(向下链)。这是我的数据表结构:
-----------------------------------------------------------------
CHILD_CODE      PARENT_CODE      CHILD_RANK      PARENT_RANK
-----------------------------------------------------------------
1               Null                  1          Null
2               1                     2          1
3               1                     2          1
4               1                     2          1
5               2                     3          2
6               2                     3          2
7               3                     3          2
8               5                     4          3

我需要获取一个父节点的完整子树。也就是说,如果我输入2作为父节点,它将返回从该节点开始一直到最后一个子节点的所有子节点。

例如... 1

输入 > PARENT_CODE = 2

输出 >

----------------------------------------------
PARENT_CODE     CHILD_CODE      CHILD_RANK
----------------------------------------------
2               5               3
2               6               3
2               8               4
----------------------------------------------

这里我们使用了 CET,就像

; WITH rekurs AS (
   SELECT child_code, child_rank
   FROM   tbl
   WHERE  parent_code = 2
   UNION ALL
   SELECT ch.child_code, ch.child_rank
   FROM   tbl ch
   JOIN   rekurs r ON ch.parent_code = r.child_code
)
SELECT 2 AS PARENT_CODE, child_code, child_rank
FROM  CTE

我们已经在程序中添加了这个CTE,但是我们正在处理大量的记录,并且遇到了一些问题。在这个CTE中,我们传递了一个单独的parent_code,以获取该特定代码的所有子代。
在这里,我们想要获取30,000个parent_code的所有子代,当我们从C#程序中使用for循环逐个将parent_code传递给CTE时,耗费的时间太长了。是否有任何方法来解决这个问题?

为什么不使用表变量传递ID,而不是一个一个地调用? - ProgrammingLlama
建议提供的解决方案很好。这也证明了以父子关系方式存储数百万行是不好的,因为在数百万条记录上进行递归查询真的很糟糕。 - KumarHarsh
2个回答

2
您可以使用以下代码:
假设您的表名为data,则:
declare @input int =2
;with report as(
   select ChildCode,ParentCode,ChildRank,ParentRank
   from data
   where ParentCode = @input
   union all
   select d.ChildCode,d.ParentCode,d.ChildRank,d.ParentRank
   from data d
   inner join report r on d.ParentCode = r.ChildCode
 )

 select * from report 

这里有一个可用的演示链接
结果:
ChildCode   ParentCode  ChildRank   ParentRank
5   2   3   2
6   2   3   2
8   5   4   3

根据下面的评论进行编辑

解释

  1. 您可以创建用户定义的表类型

    create type ParentInputs as table(ParentCode int)

  2. 将表类型参数传递给查询

查询

;with report as(
   select ChildCode,d.ParentCode,ChildRank,ParentRank
   from @data d
   inner join @input p on d.ParentCode = p.ParentCode
   union all
   select d.ChildCode,d.ParentCode,d.ChildRank,d.ParentRank
   from @data d
   inner join report r on d.ParentCode = r.ChildCode
 )
 select * from report order by ParentCode

为了演示,我创建了一个参数表而不是表类型,请查看可工作的演示
ParentCode (2,3) 的结果为:
ChildCode   ParentCode  ChildRank   ParentRank
5   2   3   2
6   2   3   2
7   3   3   2
8   5   4   3

希望这能帮到您


+1 表示解决方案可行,但是分号应该放在前一行的末尾,而不是在 with 前面的行的开头。 - Ashley Pillay
1
@AshleyPillay 对于分号,从技术上讲你是对的,但通常的做法是在 with 前面加上分号以确保不会忘记,在该特定单词之前必须有一个尾随分号,而大多数其他单词则不需要。 - Simone
这是常见的做法,因为大多数人不理解 SQL Server 抛出的关于期望在 with 之前加上分号的错误消息,所以他们只是随意添加一个分号,而不理解它是 ANSI SQL 规范中的语句终止符。我们应该尝试遵循 ANSI 规范,并习惯使用分号终止所有的 SQL 语句。(发泄完毕 :)) - Ashley Pillay
@Monah,我认为你的答案只是添加了一个参数,但并没有帮助他们解决每个调用有多个父级的问题。 - Simone

1
以下内容是否适合您:
; WITH rekurs AS (
   SELECT parent_code Root_code, child_code, child_rank
   FROM   RecursiveTable
   WHERE  parent_code IN (1, 2, 3)
   UNION ALL
   SELECT r.Root_code, ch.child_code, ch.child_Rank
   FROM   RecursiveTable ch
   JOIN   rekurs r ON ch.parent_code = r.child_code
)
SELECT Root_code, child_code, child_Rank
FROM   rekurs
ORDER BY Root_code

这是结果集:
Root_code child_code child_Rank
1         2          2
1         3          2
1         4          2
1         7          3
1         5          3
1         6          3
1         8          4
2         5          3
2         6          3
2         8          4
3         7          3

使用 IN 对于此问题不起作用,特别是有30000个父项,IN 只能用于有限的值,最多可以达到2100,所以查询将会给出错误。同时将这些值传递到 SQL,它将会变成字符串,因此你将面临另一个性能问题。 - Monah
@Monah 是的,你说得完全正确,我只是想向他展示如何在一次调用中获取多棵树;IN 可以被更改为连接或其他任何东西。 - Simone

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接