问题:根据另一列中的值修改累计和中的值。假设一个场景,要显示信用卡账号的事务处理历史以及每次事务处理洲改累计和中的值。假设一个场景,要显示信用卡账号的事务处理历史以及每次事务处理之后的当前余额。在这个例子中,将使用下面给出的视图V:
create view V (id,amt,trx)
as
select 1, 100, 'PR' from t1 union all
select 2, 100, 'PR' from t1 union all
select 3, 50, 'PY' from t1 union all
select 4, 100, 'PR' from t1 union all
select 5, 200, 'PY' from t1 union all
select 6, 50, 'PY' from t1
select * from V
ID AMT TR
-- ---------- --
1 100 PR
2 100 PR
3 50 PY
4 100 PR
5 200 PY
6 50 PY
ID列唯一标识每次事务处理。AMT列表示每次事务处理(取款或存款)涉及的金额。TRX列定义了事务处理的类型;取款是“PY”,存款是“PR”。如果TRX值是PY,则想要从累计和中减去AMT值代表的金额;如果TRX值是PR,则想要给累计和加上AMT值代表的金额。最后应该返回如下结果集:
TRX_TYPE AMT BALANCE
-------- ---------- ----------
PURCHASE 100 100
PURCHASE 100 200
PAYMENT 50 150
PURCHASE 100 250
PAYMENT 200 50
PAYMENT 50 0
解决方案
DB2和Oracle
使用窗口函数SUM OVER创建累计和,并使用CASE表达式判断事务处理的类型:
1 select case when trx = 'PY'
2 then 'PAYMENT'
3 else 'PURCHASE'
4 end trx_type,
5 amt,
6 sum(
7 case when trx = 'PY'
8 then -amt else amt
9 end
10 ) over (order by id,amt) as balance
11 from V
MySQL、PostgreSQL和SQL Server
使用标量子查询创建累计和,并使用CASE表达式判断事务处理的类型:
1 select case when v1.trx = 'PY'
2 then 'PAYMENT'
3 else 'PURCHASE'
4 end as trx_type,
5 v1.amt,
6 (select sum(
7 case when v2.trx = 'PY'
8 then -v2.amt else v2.amt
9 end
10 )
11 from V v2
12 where v2.id <= v1.id) as balance
13 from V v1
讨论
CASE表达式判断是该给累计和加上当前的AMT值还是从中减去当前的AMT值 。如果事务处理是取款,则把AMT更改为负值,这样就减少了累计和。CASE表达式的结果如下所示:
select case when trx = 'PY'
then 'PAYMENT'
else 'PURCHASE'
end trx_type,
case when trx = 'PY'
then -amt else amt
end as amt
from V
TRX_TYPE AMT
-------- ---------
PURCHASE 100
PURCHASE 100
PAYMENT -50
PURCHASE 100
PAYMENT -200
PAYMENT -50
在确定了事务处理类型之后,就可以从累计和中加上或者减去AMT值。有关窗口函数SUM OVER或标量子查询如何创建累计和的说明,请参阅“计算累计和”。