1

我有这种结构的表:

Id ParentId CountItems

我可以通过脚本计算项目的级别:

 ;WITH cteSort AS
  (
  SELECT Id AS Child, ParentId AS Parent, 1  AS [Level]
    FROM [Catalog].[Category] WHERE Id = 0 
  union ALL
  SELECT Id AS Child, ParentId AS Parent, [Level] + 1 AS [Level]
  FROM [Catalog].[Category] 
       INNER JOIN cteSort ON [Category].ParentId = cteSort.Child and Id <>0)

我想从较低级别上升到顶部,并将站在较低级别和当前 CountItems 的字段 CountItems 子项的总和放入当前 CountItems。像这样:之前

Id ParentId count 
0     0      0 
1     0      1 
2     0      1 
3     1      1 
4     1      1 
5     2      1 
6     3      1 
7     4      1 
8     4      1 

Id ParentId count
0    0        8 
1    0        6 
2    0        2  
3    1        2 
4    1        3 
5    2        1 
6    3        1 
7    4        1 
8    4        1 
4

3 回答 3

1

我自己的解决方案,将新字段插入表 [级别]:

;WITH cteSort AS
  (
  SELECT Id AS Child, ParentId  AS Parent,1  AS [Level]
    FROM table WHERE Id = 0 
  union ALL
  SELECT 
     Id AS Child,
     ParentId AS Parent,
     cteSort.[Level] + 1 AS [Level]
  FROM table 
       INNER JOIN cteSort ON table.ParentId = cteSort.Child and table.Id<>0)

UPDATE table SET [Level] = (Select [Level] from cteSort where cteSort.Child = table.Id)

declare @max int
set @max = (select top(1) [Level] from table order by [Level]  Desc)
 while (@max >0)
 begin
     UPDATE t1
        SET t1.[count] = t1.[count] + t2.cnt ,
        from table as t1 
        cross apply (Select COALESCE(SUM([count]),0) cnt from table where ParentId =t1.Id) t2
        where t1.Id in (Select Id from table where [Level] =@max)
     Set @max = @max -1
 end
于 2012-09-12T05:48:46.353 回答
1

我最近在关系表示中遇到了树的问题,所以我试图解决您的问题,但经过一些重试后,我得到以下输出:GROUP BY, HAVING, or aggregate functions are not allowed in the recursive part of a recursive common table expression当编写以下内容时

WITH sum_cte AS
(
    SELECT
       Id, ParentId, [Count]
    FROM Category c

    -- find Categories that have no child
    WHERE NOT EXISTS(SELECT 1 FROM Category WHERE ParentId = c.Id)

    UNION ALL


    SELECT
        s.ParentId
        -- find parent of current parent
        , c.ParentId
        , SUM(s.[Count])
    FROM 
        sum_cte s  
        JOIN Category c 
        ON s.ParentId = c.Id
    WHERE s.Id<>0
    GROUP BY s.ParentId, c.ParentId
)

SELECT DISTINCT * FROM sum_cte ORDER BY Id 

我认为用 CTE 解决问题是不可能的。所以我写了一个递归函数,它给出了所有孩子的总数。

CREATE FUNCTION [dbo].[GetSumOfChildren](@CategoryId INT)
RETURNS INT
AS
BEGIN
    DECLARE @sum int;
    SELECT 
        -- get sum of all children
        @sum = SUM(dbo.GetSumOfChildren(Id))
    FROM
        Category
    WHERE ParentId = @CategoryId AND ParentId <> Id

    SELECT 
        -- plus self count
        @sum = ISNULL(@sum,0) + [Count]
    FROM
        Category
    WHERE Id = @CategoryId

    RETURN @sum;
END

有了这个你的任务解决简单

SELECT Id,ParentId, dbo.GetSumOfChildren(Id) FROM Category
于 2012-09-11T13:20:12.370 回答
0

我想你的问题更多地导致了为什么?而不是一个实际的解决方案(在我的午餐中对此感到困惑)我确实有一些贡献。

在纯编程术语中,您可以使用通过父计数和要处理的节点的递归函数来完成此操作,同时保持当前叶的内部计数。在纯 SQL 中模拟这一点将是一项更有趣的尝试,因为将使用的一些编程技术很难在 SQL 中实现(如果有的话)。

我的实际想法是我没有在每行使用 som convul​​ted 子查询(这会很昂贵,具体取决于行数,并且可能需要固定数量的级别),而是将结果集转换为 XML 对象,然后使用 XQuery 来然后获取后代的数量,然后用结果更新您的结果集。不幸的是 count() 没有开关来计算所有后代,因此您必须恢复到某些子查询类型逻辑才能逐行计算。此外,这种方法似乎指向具有固定数量的级别......

这又回到了为什么?如果您将此结果集传递给 C#、Java 等编程语言以进行处理,那么在该点实现递归计算并在使用之前将其添加到结果集中会更有意义。

于 2012-09-11T13:35:31.623 回答