これはMERGE
ステートメントの優れた例です。いくつかの行を更新する必要があります.1つの行(合計量が選択された行の正確な合計でない場合は分割する必要がある行)を削除し、2つの行を挿入します( "分割"行を置き換えます)。
私が行ったように文を書くには、宣言で与えられた列名を使ってWITH
節を使用していたので、Oracle 11.2が必要です。古いバージョンのOracleでは、これを(インライン・ビューを使用して)簡単に再編成できます。
解決策は、関数やPL/SQLを必要としません(ただし、必要に応じて関数内にラップすることもできます)。それはすべて純粋なSQLです。
私の解決方法では、適切な主キーの代わりにrowid
を使用しました。ベーステーブルがrowid
の代わりに使用できるPKを持っていれば、それはもっと良いでしょう。
私はバインド変数にどのように値が与えられているかを示していませんでした。私の場合、SQL Developerでこれを実行しました。 SQL Developerでバインド変数を使用して文を実行しようとするたびに、入力用のウィンドウがポップアップします。 (私はToadも似ていると信じています。)各フロントエンドプログラムには、変数をバインド変数に割り当てる独自のメカニズムがあります。あなたは12月を行う方法
準備
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
ideどの行を「最初に」使うべきですか?あなたの例では、最後の0.10行を残しました - あなたは、その量の降順で行を使用しますか?行には他の値(テーブル内の他の列)もあります。これらの値によって、それらを互いに区別することができます。そして、渡された変数がテーブル内のすべての値の合計以上の場合、結果はどうなるでしょうか? – mathguy
@mathguy渡された値は決して合計以上ではありません。 – elene
また、どの行が最初に更新されるかは関係ありません。目標は渡された値と等しい合計ですべての行を更新することです。 – elene