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 で実装するのが (仮にあったとしても) はるかに難しいからです。

私の実際の考えでは、行ごとに複雑なサブクエリを使用するのではなく (これは、行数によってはコストが高くなり、一定数のレベルが必要になる可能性があります)、結果セットを XML オブジェクトに変換し、XQuery を使用して次に子孫の数を取得し、その結果で結果セットを更新します。残念ながら、count() にはすべての子孫をカウントするスイッチがないため、サブクエリ タイプのロジックに戻って、行ごとにカウントする必要があります。さらに、このアプローチは、固定数のレベルを持つことを示しているようです...

それを理由に戻すのはどれですか?この結果セットを C# や Java などのプログラミング言語に渡して処理する場合、その時点で再帰計算を実装し、消費する前にそれを結果セットに追加する方がはるかに理にかなっています。

于 2012-09-11T13:35:31.623 に答える