有条件 运行 总计

Conditional running total

我必须在 Redshift 中做一件有趣的事情。比如说,我有一个像这样的 table:

index,total,delta
0,3,null
1,5,2
2,10,5
3,11,1
4,null,4
5,null,6
6,null,2

其中 delta 是每个 total 与上一行的 total 之间的差异。在这里,我的 deltas 来自与我的 totals 不同的来源,因此可以接收 deltas 而不接收更新的 totals。

如何根据 delta 推算 total?像这样:

index,total,delta
0,3,null
1,5,2
2,10,5
3,11,1
4,15,4
5,21,6
6,23,2

我在 NVL(total, LAST_VALUE(total IGNORE NULLS) OVER (ORDER BY index ROWS UNBOUNDED PRECEDING) + SUM(delta) OVER (ORDER BY index ROWS UNBOUNDED PRECEDING) 附近的某个地方闲逛,但这并不能完全做到 - 我只想 SUM delta 有没有对应的total.

您可以使用:

-- creating subgroups
WITH cte AS (
  SELECT *, SUM(total IS NOT NULL::int) OVER(ORDER BY index) s
  FROM tab
)
SELECT index, 
    CASE WHEN total IS NULL 
         THEN SUM(COALESCE(total,0) + delta) OVER(PARTITION BY s ORDER BY index)
             -FIRST_VALUE(delta) OVER(PARTITION BY s ORDER BY index)
             -- running total starting from first not null total + delta
             -- decreased by first delta
         ELSE total
    END AS total
   ,delta
FROM cte
ORDER BY index;

db<>fiddle demo

输出:

┌────────┬────────┬───────┐
│ index  │ total  │ delta │
├────────┼────────┼───────┤
│     0  │     3  │       │
│     1  │     5  │     2 │
│     2  │    10  │     5 │
│     3  │    11  │     1 │
│     4  │    15  │     4 │
│     5  │    21  │     6 │
│     6  │    23  │     2 │
└────────┴────────┴───────┘

编辑:

其实不需要FIRST_VALUE:

WITH cte AS (
  SELECT *, SUM(total IS NOT NULL::int) OVER(ORDER BY index) s
  FROM tab
)
SELECT index, 
   CASE WHEN total IS NULL 
    THEN SUM(COALESCE(total,0) 
       + CASE WHEN total IS NOT NULL THEN 0 ELSE delta END) 
        OVER(PARTITION BY s ORDER BY index)
    ELSE total
   END AS total
  ,delta
FROM cte
ORDER BY index;

db<>fiddle demo2