SQL 查询、外连接、cte?需要用 "left" 值修复 运行 总数

SQL query, outer join, cte? Need to fix running total with "left" value

几天来我一直在努力纠正这个问题。基本上在acount_nogroup一组中,只需要扣除少于最大组的金额。

基本上,帐户 104 的最大组数是 99,第一个金额是 75,因为 taken 是 75,left over amount 是24,那么对于下一个B组,即使需要的数量是64,因为只剩下24,B组将只给24,之后什么都没有,所以D组将剩下0。

基本上我的table可以有这样的值

DECLARE @table AS TABLE(acc_no INT, [group] CHAR(1), [maxgroup] INT, amount INT)

INSERT INTO @table VALUES
(101, 'A', 70, 0),
(101, 'B', 70, 50),
(101, 'C', 70, 0),
(101, 'D', 70, 20),
(102, 'A', 95, 30),
(102, 'B', 95, 0),
(102, 'C', 95, 5),
(102, 'D', 95, 10),
(103, 'A', 80, 40),
(103, 'B', 80,15),
(103, 'C', 80, 10),
(103, 'D', 80, 5),
(104, 'A', 99.53, 75),
(104, 'B', 99.53,64),
(104, 'D', 99.53, 0.53),

(105, 'A', 21.5, 75),
(105, 'D', 21.5,6)



SELECT t.acc_no, 
    t.[group],
    t.maxgroup,t.amount,
    CASE WHEN t1.assigned = 0 THEN NULL ELSE t.amount END AS taken, 
    CASE WHEN t1.assigned = 0 THEN NULL ELSE (t.maxgroup - t1.assigned) END [left]
FROM @table t
OUTER APPLY(SELECT SUM([amount]) AS assigned 
            FROM @table t1 WHERE t1.acc_no = t.acc_no AND t1.[group] <= t.[group]) t1

这是我期望的结果:

 acc_no group   maxgroup    amount  taken   left
101 A   70      0   NULL    NULL
101 B   70      50  50  20
101 C   70      0   0   20
101 D   70      20  20  0
102 A   95      30  30  65
102 B   95      0   0   65
102 C   95      5   5   60
102 D   95      10  10  50
103 A   80      40  40  40
103 B   80      15  15  25
103 C   80      10  10  15
103 D   80      5   5   10
104 A   99      75  75  24
104 B   99      64  24  0    --<<
104 D   99      0   0   0
105 A   21      75  21  0
105 D   21      6   0   0

不幸的是,我的查询为 acc_no=104left 列提供了负值。

你们非常亲密:

CASE 
  WHEN t1.assigned = 0 THEN NULL 
  WHEN t.maxgroup < t1.assigned THEN 0 --<< that's it
  ELSE (t.maxgroup - t1.assigned) 
END [left]

但我的建议是:

SELECT t.acc_no, 
    t.[group],
    t.maxgroup,
    t.amount,
    CASE 
      WHEN t.amount = 0 THEN 0
      WHEN t.maxgroup < (t.running_total-t.amount) THEN 0
      WHEN t.maxgroup < t.running_total THEN t.amount - (t.running_total - t.maxgroup)
      ELSE t.amount
    END taken,
    CASE 
      WHEN t.maxgroup < t.running_total THEN 0
      ELSE t.maxgroup - t.running_total
    END [left]
FROM (
  SELECT t.acc_no, 
      t.[group],
      t.maxgroup,
      t.amount,
      SUM(t.amount) OVER(PARTITION BY t.[acc_no] ORDER BY t.[group] ROWS UNBOUNDED PRECEDING) running_total
  FROM stock t
) t
order by 1, 2

这个只会扫描一次源 table。而不是使用子查询方法的许多循环。

http://sqlfiddle.com/#!18/ce2f5/12

为了保持查询逻辑,您可以跟踪每个组的前一行总计,如下所示:

SELECT t.acc_no, 
    t.[group],
    t.maxgroup, t.amount, 
    CASE WHEN A.previous_assigned + t.amount <= t.maxgroup THEN t.amount
    ELSE CASE When (t.maxgroup - A.previous_assigned) > 0 Then (t.maxgroup - A.previous_assigned)
        ELSE 0
        END 
    END AS taken, 
    CASE WHEN  (t.maxgroup - A.previous_assigned - t.amount) <= 0 THEN 0 
    ELSE (t.maxgroup - A.previous_assigned - t.amount) 
    END AS [left]
FROM @table t
OUTER APPLY(SELECT SUM([amount]) AS assigned, (SUM([amount]) - t.amount) AS previous_assigned
            FROM @table t1 WHERE t1.acc_no = t.acc_no AND t1.[group] <= t.[group]) As A;