SQL Server:子项列的总和(仅在子项没有负值之前求和)

时间:2014-07-03 10:00:53

标签: sql sql-server sum common-table-expression

我再次遇到一个小问题(我希望很小)。

我有一个父母孩子hirarchy,其中一方父母可以有多个孩子,一个孩子可以再生多个孩子等等。

每个父母和子女都有一定数额(价值),父母可以补偿儿童的任何遗失金额。

这是我的表:

CREATE TABLE #Test
(
 ID INTEGER NOT NULL
,ParentID INTEGER
,NAME VARCHAR(20)
,value INTEGER
)

TESTDATA:

INSERT INTO #Test ( ID, ParentID, NAME, value ) VALUES ( 1, NULL, 'MainStore', 1 ) , ( 2, 1, 'Substore1', 3 ) , ( 3, 1, 'Substore2', 10 ) , ( 4, 2, 'Sub1Substore1', -1 ) , ( 5, 2, 'Sub1Substore2', 1 ) , ( 6, 3, 'Sub2Substore1', 10 )

要显示父亲关系,我已尝试使用CTE:

;WITH    CTE
      AS ( SELECT   ID
                   ,ParentID
                   ,Name
                   ,Value
                   ,0 AS LEVEL
                   ,CAST('' AS INTEGER) AS ID_Parent
           FROM     #Test
           WHERE    ParentID IS NULL
           UNION ALL
           SELECT   child.ID
                   ,child.ParentID
                   ,child.Name
                   ,child.Value
                   ,parent.Level + 1
                   ,parent.ID
           FROM     CTE parent
                    JOIN #Test child ON child.ParentID = parent.ID
         )

如您所见,Substore1有2个子级(Sub1Substore1和Sub1Substore2),Substore1的值为3,Sub1Substore1为-1,Sub1Substore2为1。

Sub1Substore1是Substore1的子节点,父节点可以补偿子节点的缺失值。

我想要的输出应该如下所示:

ID          ParentID    Name                 Value       LEVEL       ID_Parent   FreeValues
----------- ----------- -------------------- ----------- ----------- ----------- -----------
1           NULL        MainStore            1           0           0           1
2           1           Substore1            3           1           1           2
3           1           Substore2            10          1           1           8
4           2           Sub1Substore1        -1          2           2           0
5           2           Sub1Substore2        1           2           2           1
6           3           Sub2Substore1        -2          2           3           0

可悲的是,SQL Fiddle网站暂时不适合我,但我稍后将在SQL Fiddle上提供此示例。

1 个答案:

答案 0 :(得分:1)

编辑:由于误解了任务,重写了整个答案。

这可能可以通过常见的表表达式优雅地解决,但由于CTE缺乏对多个递归引用的支持,因此这个任务似乎变得过于复杂,我无法处理。

然而,这是一个不太优雅的解决方案,应该为你做的伎俩。请注意,我假设父母的ID总是小于它的直接子女的身份。如果您应该能够更改已插入的行"即时",这可能会成为一个问题。无论如何,你走了:

--Declare temp table.
DECLARE @Temp TABLE
(
 ID INTEGER NOT NULL
,ParentID INTEGER
,NAME VARCHAR(20)
,value INTEGER
,FreeValues INTEGER
,NeedFromParent INTEGER
,ChildrenNeed INTEGER
);

--Other variables
DECLARE @ID INTEGER
DECLARE @ParentID INTEGER
DECLARE @Name VARCHAR(20)
DECLARE @value INTEGER
DECLARE @FreeValues INTEGER
DECLARE @NeedFromParent INTEGER
DECLARE @ChildrenNeed INTEGER

--Loop with cursor to calculate FreeValues
DECLARE cur CURSOR FOR SELECT id, parentId, Name, Value FROM #test 
ORDER BY ID DESC -- NOTE! Assumed that Parent's ID < Child's ID.
OPEN cur
FETCH NEXT FROM cur INTO @ID, @ParentID, @Name, @value
WHILE @@FETCH_STATUS = 0
BEGIN
  SELECT @ChildrenNeed = CASE
   WHEN SUM(temp.NeedFromParent) IS NULL THEN 0 
   ELSE SUM(temp.NeedFromParent) END
  FROM @temp temp WHERE temp.ParentID=@ID AND temp.NeedFromParent > 0

  IF @ChildrenNeed IS NULL SET @ChildrenNeed = 0

  IF @Value - @ChildrenNeed < 0 
    SET @NeedFromParent = @Value - @ChildrenNeed
  ELSE
    SET @NeedFromParent = 0

  SET @NeedFromParent = -@NeedFromParent

  IF @NeedFromParent = 0 
    SET @FreeValues = @value - @ChildrenNeed
  ELSE
    SET @FreeValues = 0

  INSERT INTO @Temp 
    VALUES(@ID, @ParentID, @Name, @value, @FreeValues, @NeedFromParent, @ChildrenNeed)
  FETCH NEXT FROM cur INTO @ID, @ParentID, @Name, @value
END 
CLOSE cur;
DEALLOCATE cur;

-- Join with recursively calculated Level.
;WITH CTE
 AS ( SELECT ID ,ParentID,0 AS [Level]
      FROM  #Test WHERE ParentID IS NULL
      UNION ALL
      SELECT child.ID,child.ParentID,parent.Level + 1
      FROM CTE parent INNER JOIN #Test child ON child.ParentID = parent.ID
   ) 
SELECT t1.ID, t1.ParentID, t1.Name, t1.Value, cte.[Level], t1.FreeValues 
FROM CTE cte LEFT JOIN @temp t1 ON t1.ID = cte.ID 
ORDER BY ID