我需要在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
答案 0 :(得分:3)
这是达到你想要的一种方式,虽然它与你上面的方法略有不同:
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的行设置为开始时完成,因此将首先计算它们的直接后代,然后计算这些行的后代等等。
答案 1 :(得分:2)
玩了一下之后我觉得我明白了。我添加了一个顶级ID,我在CTE的Root中设置了它。然后只需为所有递归添加顶级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