我在 SQL 中有一个收入表,其中包含日期和收入列。我想创建一个防止负收入值的逻辑,以便将任何负收入值设置为 0,并从接下来几个月的收入中减去负数,直到完全抵消。
比如我有以下收入数据:
日期 | 收入 |
---|---|
2018-09-01 | 1200 |
2018-08-01 | 400 |
2018-07-01 | -1000 |
2018-06-01 | 800 |
2018-05-01 | 600 |
2018-04-01 | 200 |
2018-03-01 | -200 |
2018-02-01 | 400 |
2018-01-01 | 200 |
预期输出应该是:
日期 | 收入 |
---|---|
2018-09-01 | 600 |
2018-08-01 | 0 |
2018-07-01 | 0 |
2018-06-01 | 800 |
2018-05-01 | 600 |
2018-04-01 | 0 |
2018-03-01 | 0 |
2018-02-01 | 400 |
2018-01-01 | 200 |
这里是一些入门代码
WITH revenue_table AS (
SELECT '2018-09-01' AS date, 1200 AS revenue UNION ALL
SELECT '2018-08-01' AS date, 400 AS revenue UNION ALL
SELECT '2018-07-01' AS date, -1000 AS revenue UNION ALL
SELECT '2018-06-01' AS date, 800 AS revenue UNION ALL
SELECT '2018-05-01' AS date, 600 AS revenue UNION ALL
SELECT '2018-04-01' AS date, 200 AS revenue UNION ALL
SELECT '2018-03-01' AS date, -200 AS revenue UNION ALL
SELECT '2018-02-01' AS date, 400 AS revenue UNION ALL
SELECT '2018-01-01' AS date, 200 AS revenue
)
select * from revenue_table
我不确定如何解决这个问题。任何人都可以提出解决方案或提供一些实现此逻辑的示例代码吗?
如果我正确地回答了这个问题,我们确实需要在这里递归,以便我们可以迭代地将负数分配到以下行。
least
和 greatest
应该足够好算术:
with recursive
data as (
select r.*, row_number() over(order by date) rn from revenue_table r
),
rcte (date, old_revenue, rn, new_revenue, rest) as (
select null::date, 0, 0::bigint, 0, 0
union all
select d.*, greatest(d.revenue + r.rest, 0), least(d.revenue + r.rest, 0)
from rcte r
inner join data d on d.rn = r.rn + 1
)
select date, old_revenue, new_revenue
from rcte
where rn > 0 order by date desc
约会 | old_revenue | 新收入 |
---|---|---|
2018-09-01 | 1200 | 600 |
2018-08-01 | 400 | 0 |
2018-07-01 | -1000 | 0 |
2018-06-01 | 800 | 800 |
2018-05-01 | 600 | 600 |
2018-04-01 | 200 | 0 |
2018-03-01 | -200 | 0 |
2018-02-01 | 400 | 400 |
2018-01-01 | 200 | 200 |