【问题标题】:Applying recursion to a SQL Server query将递归应用于 SQL Server 查询
【发布时间】:2014-06-11 23:25:54
【问题描述】:

SQL Server 中的表具有多代父子引用的映射。

我必须达到结果:

Level No || Child Count

所以,我有以下查询:

SELECT 
    'L1' LEVEL, COUNT(ChildRef) CHILD 
FROM 
    [dbo].[TOMatriX] 
WHERE 
    ParentRef = 1

UNION ALL

SELECT 
   'L2' LEVEL, COUNT(ChildRef) CHILD 
FROM 
   [dbo].[TOMatriX]
WHERE 
   ParentRef IN (SELECT ChildRef FROM [dbo].[TOMatriX] WHERE ParentRef = 1)

UNION ALL

SELECT 
   'L3' LEVEL, COUNT(ChildRef) CHILD 
FROM 
   [dbo].[TOMatriX]
WHERE 
   ParentRef IN (SELECT ChildRef FROM [dbo].[TOMatriX]
                 WHERE ParentRef IN (SELECT ChildRef FROM [dbo].[TOMatriX] 
                                     WHERE ParentRef = 1)
                )

UNION ALL

SELECT 
   'L4' LEVEL, COUNT(ChildRef) CHILD 
FROM 
   [dbo].[TOMatriX]
WHERE 
   ParentRef IN (SELECT ChildRef FROM [dbo].[TOMatriX]
                 WHERE ParentRef IN (SELECT ChildRef FROM [dbo].[TOMatriX]
                                     WHERE ParentRef IN (SELECT ChildRef 
                                                         FROM [dbo].[TOMatriX] 
                                                         WHERE ParentRef = 1)
                                    )
                )

如何使这个查询动态而不是像这样硬编码,因为级别也可以超过 4。

如何使用Common Table Expressions 或其中的任何递归?

【问题讨论】:

标签: sql sql-server sql-server-2008 recursion recursive-query


【解决方案1】:

假设我们有下表:

create table #t1 (childref int, parentref int)
go
insert #t1 values
(1, null),
(2, 1),
(3, 1),
(4, 2),
(5, 2),
(6, 4),
(7, 4),
(8, 5),
(9, 6)
go

我们可以使用递归 CTE 遍历层次结构并计算每个级别的项目:

;with x as (
    select childref, 0 as lvl
    from #t1
    where parentref is null

    union all

    select #t1.childref, x.lvl+1
    from #t1
    inner join x on #t1.parentref = x.childref
)
select lvl, count(*)
from x
group by lvl

这是您想要的结果。让我们看看它是如何工作的。

递归 CTE 有两部分(为了简单起见):锚点和递归部分。锚点:

    select childref, 0 as lvl
    from #t1
    where parentref is null

执行一次,结果暂存。然后递归成员被执行

    select #t1.childref, x.lvl+1
    from #t1
    inner join x on #t1.parentref = x.childref

看到内部连接了吗?这里的“x”实际上是对锚成员结果的引用。我们要加入的列必须包含在选择列表中。

此步骤的结果被存储,并作为下一步的基础。

递归成员再次执行,这次加入上一步的结果。以此类推,只要递归步骤返回任意行,或者没有达到最大递归。

UNION ALL 这里只是将这两者连接在一起的语法。

lvl 被添加到选择中以表示当前级别,并在每一步递增。

如果你只是在 CTE 之后select * from x,你可以看到原始输出。我们所做的是按 lvl 对其进行分组并计算行数。

【讨论】:

    猜你喜欢
    • 2014-12-19
    • 2012-12-05
    • 1970-01-01
    • 2014-10-10
    • 2011-02-21
    • 1970-01-01
    • 2017-12-27
    • 1970-01-01
    相关资源
    最近更新 更多