2016-12-07 2 views
0

に基づいてレコードを更新する関数を作成します:オラクル:量と種類とテーブルが与えられたパラメータ

| AMOUNT | PAY_TYPE | 
| 0.50 | D  | 
| 0.50 | D  | 
| 0.50 | D  | 
| 0.10 | D  | 
| 0.50 | D  | 
| 0.50 | D  | 

私は「D」からpay_typeを更新し、入力パラメータ(量)との関数を記述しようとしています渡されたパラメーターと等しい合計を持つ行の場合は 'A'です。 Iが機能する2.50を渡す場合

たとえば、結果は次のようになります。私は2つの部分のみに一列に分割しなければならない機能以外の機能2.40に渡す場合

また
| AMOUNT | PAY_TYPE | 
| 0.50 | A  | 
| 0.50 | A  | 
| 0.10 | D  | 
| 0.50 | A  | 
| 0.50 | A  | 
| 0.50 | A  | 

問題ですその更新テーブルの後に

+0

ideどの行を「最初に」使うべきですか?あなたの例では、最後の0.10行を残しました - あなたは、その量の降順で行を使用しますか?行には他の値(テーブル内の他の列)もあります。これらの値によって、それらを互いに区別することができます。そして、渡された変数がテーブル内のすべての値の合計以上の場合、結果はどうなるでしょうか? – mathguy

+0

@mathguy渡された値は決して合計以上ではありません。 – elene

+0

また、どの行が最初に更新されるかは関係ありません。目標は渡された値と等しい合計ですべての行を更新することです。 – elene

答えて

0

これは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 
関連する問題