【问题标题】:How to sum a column in SQL Server recursive cte for optimization?如何对 SQL Server 递归 cte 中的列求和以进行优化?
【发布时间】:2017-09-14 06:09:29
【问题描述】:

我有下表包含分层数据:

FolderId ParentFolderId NumberOfAffectedItems
---------------------------------------------
1           NULL        2
2           1           3
3           2           5
4           2           3
5           1           0

我想在每个文件夹及其所有子文件夹下查找受影响项目的数量。我可以写一个递归 cte,它可以产生以下结果,然后通过 group by 我可以找到我想要的。

正常递归 CTE:

WITH FolderTree AS
(
    SELECT
        fsa.FolderId AS ParentFolderId,
        fsa.FolderId AS ChildFolderId,          
        fsa.NumberOfReportsAffected
    FROM
        FoldersWithNumberOfReportsAffected fsa

    UNION ALL

    SELECT
        ft.ParentFolderId,
        fsa.FolderId AS ChildFolderId,                  
        fsa.NumberOfReportsAffected
    FROM
        FoldersWithNumberOfReportsAffected fsa
    INNER JOIN
        FolderTree ft ON fsa.ParentFolderId = ft.ChildFolderId          
  )

结果:

ParentFolderId ChildFolderId NumberOfAffectedItems
--------------------------------------------------
1               1           2
1               2           3
1               3           5
1               4           3
1               5           0
2               2           3
2               3           5
2               4           3
3               3           5
4               4           3
5               5           0

但我想优化它,我想从叶子孩子开始,而 通过 CTE 本身,我想计算 NumberOfAffectedItems

预期 CTE

WITH FolderTree AS
(
    SELECT
        fsa.FolderId AS LeafChildId,
        fsa.FolderId AS ParentFolderId,         
        fsa.NumberOfReportsAffected
    FROM
        FoldersWithNumberOfReportsAffected fsa
    LEFT JOIN
        FoldersWithNumberOfReportsAffected f ON fsa.folderid = f.ParentfolderId
    WHERE
        f.ParentfolderId is null -- this is finding leaf child

    UNION ALL

    SELECT
        ft.LeafChildId,
        fsa.FolderId AS ParentFolderId,                 
        fsa.NumberOfReportsAffected + ft.NumberOfReportsAffected AS [ComputedResult]
    FROM
        FoldersWithNumberOfReportsAffected fsa
    INNER JOIN 
        FolderTree ft ON fsa.FolderId = ft.ParentFolderId
  )

结果:

LeafChildId ParentFolderId ComputedNumberOfAffectedItems
---------------------------------------------------------
3           3               5
3           2               8
3           1               10
4           4               3
4           2               5
4           1               7
5           5               0
5           1               2

如果我按ParentFolderId分组,我会得到错误的结果,原因是在CTE中进行计算时,从多个访问相同的父文件夹 孩子,因此导致错误的结果。我想知道我们是否可以在通过 CTE 本身的同时计算结果。

【问题讨论】:

  • 你能把你的cte贴出来吗?
  • 这是我现在使用的 cte,结果正确
  • cte 在哪里?我只看到结果...
  • 我已经更新了问题中的 cte

标签: sql-server recursive-cte


【解决方案1】:

请检查以下解决方案。我使用您的 cte 作为基础并将计算(作为 x 列)添加到它:

DECLARE @t TABLE(
  FolderID INT
 ,ParentFolderID INT
 ,NumberOfAffectedItems INT
);

INSERT INTO @t VALUES (1           ,NULL        ,2)
                     ,(2           ,1           ,3)
                     ,(3           ,2           ,5)
                     ,(4           ,2           ,3)
                     ,(5           ,1           ,0);


WITH FolderTree AS
(
    SELECT 1lvl,
        fsa.FolderId AS LeafChildId,
        fsa.ParentFolderId AS ParentFolderId,
        fsa.NumberOfAffectedItems
    FROM
        @t fsa
    LEFT JOIN
        @t f ON fsa.folderid = f.ParentfolderId
    WHERE
        f.ParentfolderId is null -- this is finding leaf child

    UNION ALL

    SELECT lvl + 1,
        ft.LeafChildId,
        fsa.ParentFolderId,                 
        fsa.NumberOfAffectedItems
    FROM
        FolderTree ft
    INNER JOIN @t fsa
        ON fsa.FolderId = ft.ParentFolderId
  )
SELECT  LeafChildId,
        ISNULL(ParentFolderId, LeafChildId) ParentFolderId,
        NumberOfAffectedItems,
        SUM(NumberOfAffectedItems) OVER (PARTITION BY LeafChildId ORDER BY ISNULL(ParentFolderId, LeafChildId) DESC) AS x
  FROM FolderTree
  ORDER BY 1, 2 DESC
  OPTION (MAXRECURSION 0)

结果:

LeafChildId ParentFolderId  NumberOfAffectedItems   x
3           3               2                       2
3           2               5                       7
3           1               3                       10
4           4               2                       2
4           2               3                       5
4           1               3                       8
5           5               2                       2
5           1               0                       2

【讨论】:

  • 感谢@Tyron78,但是由于您使用的 CTE 与我使用的相同,因此它在求和之前返回相同数量的原始结果,我想从叶子子节点开始遍历,同时通过 cte本身我想计算结果,我不知道它是否可能。请查看问题中的第二个 cte 以供参考。
  • 我修改了查询以便使用第二个 cte 中建议的叶子 cte。
  • P.S.:此外,我不得不修改你的第二个 cte 中的连接 - 它产生了太多记录。
  • 感谢@Tyron78,但是如果我想知道folderid 1 下有多少受影响的项目,现在您的查询将给出20,但实际计数是13。
  • 不完全是。您可以总结父文件夹 ID (10 + 8 + 2),因为提到的受影响项目是叶子 3、4 和 5 的相应聚合 - 定义为叶子的那些。从叶子开始,您无法计算/汇总非叶子成员的正确项目数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-13
  • 2010-11-03
  • 2012-04-23
相关资源
最近更新 更多