Oracle SQL 递归加值
Oracle SQL recursive adding values
我在 table
中有以下数据
Period Total_amount R_total
01/01/20 2 2
01/02/20 5 null
01/03/20 3 null
01/04/20 8 null
01/05/20 31 null
根据以上数据,我想有以下情况。
Period Total_amount R_total
01/01/20 2 2
01/02/20 5 3
01/03/20 3 0
01/04/20 8 8
01/05/20 31 23
附加数据
01/06/20 21 0 (previously it would be -2)
01/07/20 25 25
01/08/20 29 4
附加数据的模式是:
如果 total_amount < previous(r_total) 那么 0
根据填充的数据,我们可以发现模式是:
R_total = total_amount - 上一个(R_total)
你能帮我解决这个问题吗?
使用 window 函数可能可行,但最简单的方法可能是递归 CTE:
with t as (
select t.*, row_number() over (order by period) as seqnum
from yourtable t
),
cte(period, total_amount, r_amount, seqnum) as (
select period, total_amount, r_amount, seqnum
from t
where seqnum = 1
union all
select t.period, t.total_amount, t.total_amount - cte.r_amount, t.seqnum
from cte join
t
on t.seqnum = cte.seqnum + 1
)
select *
from cte;
这个问题明确地讨论了“递归地”添加值。如果你想用其他机制解决这个问题,你可能会详细解释逻辑并询问是否有非递归CTE解决方案。
正如 Gordon Linoff 所怀疑的那样,用解析函数可以解决这个问题。好处是查询可能会快得多。为这种好处付出的代价是你需要事先做一些数学运算(在考虑“编程”和“计算机”之前)。
一些初等算术表明 R_TOTAL 是 TOTAL_AMOUNT 的交替和。这可以通过使用 ROW_NUMBER()(获取符号)然后使用解析 SUM() 轻松安排,如下所示。
Table 设置:
create table sample_data (period, total_amount) as
select to_date('01/01/20', 'mm/dd/rr'), 2 from dual union all
select to_date('01/02/20', 'mm/dd/rr'), 5 from dual union all
select to_date('01/03/20', 'mm/dd/rr'), 3 from dual union all
select to_date('01/04/20', 'mm/dd/rr'), 8 from dual union all
select to_date('01/05/20', 'mm/dd/rr'), 31 from dual
;
查询和结果:
with
prep (period, total_amount, sgn) as (
select period, total_amount,
case mod(row_number() over (order by period), 2) when 0 then 1 else -1 end
from sample_data
)
select period, total_amount,
sgn * sum(sgn * total_amount) over (order by period) as r_total
from prep
;
PERIOD TOTAL_AMOUNT R_TOTAL
-------- ------------ ----------
01/01/20 2 2
01/02/20 5 3
01/03/20 3 0
01/04/20 8 8
01/05/20 31 23
我在 table
中有以下数据Period Total_amount R_total
01/01/20 2 2
01/02/20 5 null
01/03/20 3 null
01/04/20 8 null
01/05/20 31 null
根据以上数据,我想有以下情况。
Period Total_amount R_total
01/01/20 2 2
01/02/20 5 3
01/03/20 3 0
01/04/20 8 8
01/05/20 31 23
附加数据
01/06/20 21 0 (previously it would be -2)
01/07/20 25 25
01/08/20 29 4
附加数据的模式是: 如果 total_amount < previous(r_total) 那么 0
根据填充的数据,我们可以发现模式是: R_total = total_amount - 上一个(R_total)
你能帮我解决这个问题吗?
使用 window 函数可能可行,但最简单的方法可能是递归 CTE:
with t as (
select t.*, row_number() over (order by period) as seqnum
from yourtable t
),
cte(period, total_amount, r_amount, seqnum) as (
select period, total_amount, r_amount, seqnum
from t
where seqnum = 1
union all
select t.period, t.total_amount, t.total_amount - cte.r_amount, t.seqnum
from cte join
t
on t.seqnum = cte.seqnum + 1
)
select *
from cte;
这个问题明确地讨论了“递归地”添加值。如果你想用其他机制解决这个问题,你可能会详细解释逻辑并询问是否有非递归CTE解决方案。
正如 Gordon Linoff 所怀疑的那样,用解析函数可以解决这个问题。好处是查询可能会快得多。为这种好处付出的代价是你需要事先做一些数学运算(在考虑“编程”和“计算机”之前)。
一些初等算术表明 R_TOTAL 是 TOTAL_AMOUNT 的交替和。这可以通过使用 ROW_NUMBER()(获取符号)然后使用解析 SUM() 轻松安排,如下所示。
Table 设置:
create table sample_data (period, total_amount) as
select to_date('01/01/20', 'mm/dd/rr'), 2 from dual union all
select to_date('01/02/20', 'mm/dd/rr'), 5 from dual union all
select to_date('01/03/20', 'mm/dd/rr'), 3 from dual union all
select to_date('01/04/20', 'mm/dd/rr'), 8 from dual union all
select to_date('01/05/20', 'mm/dd/rr'), 31 from dual
;
查询和结果:
with
prep (period, total_amount, sgn) as (
select period, total_amount,
case mod(row_number() over (order by period), 2) when 0 then 1 else -1 end
from sample_data
)
select period, total_amount,
sgn * sum(sgn * total_amount) over (order by period) as r_total
from prep
;
PERIOD TOTAL_AMOUNT R_TOTAL
-------- ------------ ----------
01/01/20 2 2
01/02/20 5 3
01/03/20 3 0
01/04/20 8 8
01/05/20 31 23