5

我需要在 SQL Server 中进行递归求和。我想要一个存储过程,我可以在其中传递父 ID,然后返回链接到该父 ID 的所有孩子(和孩子的孩子)的总数。

这是我到目前为止所拥有的

IF object_id('tempdb..#Averages') IS NOT NULL
BEGIN
   DROP TABLE #Averages
END


CREATE TABLE #Averages
(
ID INT PRIMARY KEY CLUSTERED IDENTITY(1,1),
Name VARCHAR(255),
ParentID int,
Value INT
)

INSERT INTO #Averages(Name,ParentID,Value)VALUES('Fred',NULL,1)
INSERT INTO #Averages(Name,ParentID,Value)VALUES('Bets',NULL,1)

INSERT INTO #Averages(Name,ParentID,Value)(SELECT 'Wynand',ID,21 FROM #Averages WHERE      Name = 'Fred'  )

INSERT INTO #Averages(Name,ParentID,Value)(SELECT 'Dewald',ID,27 FROM #Averages WHERE     Name = 'Fred'  )
INSERT INTO #Averages(Name,ParentID,Value)(SELECT 'Katelynn',ID,1 FROM #Averages WHERE Name = 'Dewald'  )

INSERT INTO #Averages(Name,ParentID,Value)(SELECT 'Jacques',ID,28 FROM #Averages WHERE Name = 'Bets'  )
INSERT INTO #Averages(Name,ParentID,Value)(SELECT 'Luan',ID,4 FROM #Averages WHERE Name = 'Jacques'  )
INSERT INTO #Averages(Name,ParentID,Value)(SELECT 'Ruben',ID,2 FROM #Averages WHERE Name = 'Jacques'  )


;WITH Personal AS
(
SELECT N=1, ID,Name,ParentID,Value
FROM #Averages 
WHERE ParentID IS NULL
UNION ALL
SELECT N+1, Av.ID,Av.Name,Av.ParentID,Av.Value
FROM #Averages Av
INNER JOIN  Personal P ON P.ID = Av.ParentID
)

SELECT Name,
    SUM(Value) as Total
FROM Personal
WHERE N<=3
GROUP BY Name
4

2 回答 2

3

这是实现您想要的一种方法,尽管它与您上面的方法略有不同:

SQLFiddle

Create Table #Ancestors (
    ID int
  ,  Name VARCHAR(255)  
  ,  ParentID int
  ,  AncestryCompleteTF tinyint
  ,  Ancestors varchar(max)
  ,  TotalValue int    
)

INSERT INTO #Ancestors
SELECT
    ID
  , Name
  , ParentID
  , CASE ISNULL(ParentID, 0)
     WHEN 0 THEN 1
     ELSE 0
    END
  , CONVERT(VARCHAR, ISNULL(ParentID, ''))
  , Value
FROM
   Averages

WHILE EXISTS (SELECT * FROM #Ancestors WHERE AncestryCompleteTF = 0) 
BEGIN
  UPDATE C SET 
    C.Ancestors = P.Ancestors + ',' + CONVERT(VARCHAR, P.ID),
    C.AncestryCompleteTF = 1,
    C.TotalValue = P.TotalValue + C.TotalValue
  FROM #Ancestors C 
    INNER JOIN #Ancestors P ON (C.ParentID = P.ID) 
    AND P.AncestryCompleteTF = 1
END

SELECT 
  Name
, TotalValue 
FROM 
  #Ancestors

基本上我创建了一个临时表,并使用一个while循环来不断更新已经计算了父行的行的总数(因为这只是将当前行的总数添加到父行的总数的情况)直到所有行已经计算过了。ParentID 为 null 的行设置为开始完成,因此将首先计算它们的直接后代,然后是这些行的后代等。

于 2012-07-10T08:33:52.397 回答
2

玩了一会儿后,我想我明白了。我添加了一个顶级 ID,我在 CTE 的根中设置了它。然后只需为所有递归添加顶级 id。

最后我只求和,基本上使用 TopLevelId 加入顶级表。

IF object_id('tempdb..#Averages') IS NOT NULL
BEGIN
   DROP TABLE #Averages
END

CREATE TABLE #Averages
(
    ID INT PRIMARY KEY CLUSTERED IDENTITY(1,1),
    Name VARCHAR(255),
    ParentID int,
    Value INT
)

 INSERT INTO #Averages(Name,ParentID,Value)VALUES('Fred',NULL,1)
 INSERT INTO #Averages(Name,ParentID,Value)VALUES('Bets',NULL,1)

 INSERT INTO #Averages(Name,ParentID,Value)(SELECT 'Wynand',ID,21 FROM #Averages WHERE Name = 'Fred'  )

 INSERT INTO #Averages(Name,ParentID,Value)(SELECT 'Dewald',ID,27 FROM #Averages WHERE Name = 'Fred'  )
 INSERT INTO #Averages(Name,ParentID,Value)(SELECT 'Katelynn',ID,1 FROM #Averages WHERE Name = 'Dewald'  )

 INSERT INTO #Averages(Name,ParentID,Value)(SELECT 'Jacques',ID,28 FROM #Averages WHERE Name = 'Bets'  )
 INSERT INTO #Averages(Name,ParentID,Value)(SELECT 'Luan',ID,4 FROM #Averages WHERE Name = 'Jacques'  )
 INSERT INTO #Averages(Name,ParentID,Value)(SELECT 'Ruben',ID,2 FROM #Averages WHERE Name = 'Jacques'  )


;WITH Personal AS
(
    SELECT N=1, 
        ID,
        Name,
        ParentID,
        Value,
        TopLevelID =ID
    FROM #Averages 
    WHERE ParentID IS NULL

    UNION ALL

    SELECT N+1, 
        Av.ID,
        Av.Name,
        Av.ParentID,
        Av.Value,
        TopLevelID =P.TopLevelID
    FROM #Averages Av
    INNER JOIN  Personal P ON P.ID = Av.ParentID
)

SELECT SUM(P.Value) AS Total,
        A.Name
FROM Personal P
INNER JOIN #Averages A on A.ID = P.TopLevelID
GROUP BY A.Name
于 2012-07-10T08:53:35.650 回答