给出一个包含金额和类型的表:
%
我尝试编写一个带有输入参数(金额)的函数,该函数更新来自' D'到' A'对于总和等于传递参数的行。
例如,如果我将2.50传递给function,结果应如下所示:
| AMOUNT | PAY_TYPE |
| 0.50 | D |
| 0.50 | D |
| 0.50 | D |
| 0.10 | D |
| 0.50 | D |
| 0.50 | D |
另外问题是如果我传递给函数2.40而不是函数应该将一行分成两部分并且仅在该更新表之后。
答案 0 :(得分:0)
这是MERGE
陈述力量的绝佳例证。我们需要更新一些行,可能删除一行(如果总量不是所选行的确切总和,则必须拆分的行)并插入两行(再次,替换" split"行)。
按照我的方式编写语句需要Oracle 11.2,因为我使用了WITH
子句,并在声明中给出了列名;但是对于旧版本的Oracle,这可以很容易地重新排列(使用内联视图)。
解决方案不需要任何类型的函数或PL / SQL(当然,如果需要,它可以包含在函数中)。它都是纯粹的SQL。
在我的解决方案中,我使用rowid
代替正确的主键。如果基表具有可用于代替rowid
的PK,那将会更好。
我没有说明绑定变量是如何赋值的。就我而言,我在SQL Developer中运行它;每当您尝试在SQL Developer中运行带有绑定变量的语句时,都会弹出一个输入窗口。 (我相信Toad很相似。)每个前端程序都有自己的机制来分配值来绑定变量。
<强>制备强>
create table inputs as
select 0.50 amount, 'D' pay_type from dual union all
select 0.50, 'D' from dual union all
select 0.50, 'D' from dual union all
select 0.10, 'D' from dual union all
select 0.50, 'D' from dual union all
select 0.50, 'D' from dual
;
commit;
select * from inputs;
AMOUNT PAY_TYPE
------ --------
0.5 D
0.5 D
0.5 D
0.1 D
0.5 D
0.5 D
MERGE
声明
merge into inputs i
using (
with prep ( amount, pay_type, rn, l_amt, c_amt ) as (
select amount, pay_type, rowid as rn,
coalesce(sum(amount) over (order by rowid
rows between unbounded preceding and 1 preceding), 0),
sum(amount) over (order by rowid)
from inputs
)
select amount, pay_type, rn, c_amt
from prep
where l_amt < :input_value
union all
select :input_value - l_amt, 'A', null, null
from prep
where :input_value > l_amt and :input_value < c_amt
union all
select c_amt - :input_value, 'D', null, null
from prep
where :input_value > l_amt and :input_value < c_amt
) x
on (i.rowid = x.rn)
when matched
then update set i.pay_type = 'A'
delete where :input_value < c_amt
when not matched
then insert values (x.amount, x.pay_type)
;
7 rows merged.
<强>结果强>
select * from inputs;
AMOUNT PAY_TYPE
------ --------
0.5 A
0.5 A
0.5 A
0.1 A
0.5 A
0.1 D
0.4 A