外側の選択でのみ列のエイリアスを参照できるため、各列の以前の値をすべて再計算しない限り、各レベルをネストする必要があります。これは少し醜いです:
select bt, cno, amt, ths, fivhun, hund, fif, twenty, tens, fives, twos,
trunc((amt-(ths*1000)-(fivhun*500)-(hund*100)-(fif*50)-(twenty*20)
-(tens*10)-(fives*5)-(twos*2))/1) as ones
from (
select bt, cno, amt, ths, fivhun, hund, fif, twenty, tens, fives,
trunc((amt-(ths*1000)-(fivhun*500)-(hund*100)-(fif*50)-(twenty*20)
-(tens*10)-(fives*5))/2) as twos
from (
select bt, cno, amt, ths, fivhun, hund, fif, twenty, tens,
trunc((amt-(ths*1000)-(fivhun*500)-(hund*100)-(fif*50)-(twenty*20)
-(tens*10))/5) as fives
from (
select bt, cno, amt, ths, fivhun, hund, fif, twenty,
trunc((amt-(ths*1000)-(fivhun*500)-(hund*100)-(fif*50)
-(twenty*20))/10) as tens
from (
select bt, cno, amt, ths, fivhun, hund, fif,
trunc((amt-(ths*1000)-(fivhun*500)-(hund*100)
-(fif*50))/20) as twenty
from (
select bt, cno, amt, ths, fivhun, hund,
trunc((amt-(ths*1000)-(fivhun*500)
-(hund*100))/50) as fif
from (
select bt, cno, amt, ths, fivhun,
trunc((amt-(ths*1000)-(fivhun*500))/100) as hund
from (
select bt, cno, amt, ths,
trunc((amt-trunc(ths*1000))/500) as fivhun
from (
select bt, cno, amt,
trunc(amt/1000) as ths from employer
)
)
)
)
)
)
)
);
...次のようなものが得られます:
BT CNO AMT THS FIVHUN HUND FIF TWENTY TENS FIVES TWOS ONES
--- --- ---------------- ------- ------ ---- --- ------ ---- ----- ---- ----
1 2 123,456,789 123456 1 2 1 1 1 1 2 0
3 4 87,654,321 87654 0 3 0 1 0 0 0 1
5 6 1,234,567 1234 1 0 1 0 1 1 1 0
それほどきれいではありませんが、主に私自身の娯楽のための再帰的なバージョンです。
with t as (
select bt, cno, amt, x,
case x when 1 then 1000 when 2 then 500 when 3 then 100
when 4 then 50 when 5 then 20 when 6 then 10 when 7 then 5
when 8 then 2 when 9 then 1 end as bill
from employer
cross join (select level as x from dual connect by level < 10)
),
r (bt, cno, amt, x, y, running) as (
select t.bt, t.cno, t.amt, 0 as x, 0 as y, 0 as running
from t
where t.x = 1 -- could be any x, just want one row per bt/cno
union all
select t.bt, t.cno, t.amt, t.x,
trunc((t.amt - r.running)/t.bill) as y,
r.running + (t.bill * trunc((t.amt - r.running)/t.bill)) as running
from t
join r on r.bt = t.bt and r.cno = t.cno and r.x = t.x - 1
)
select bt, cno, amt,
max(case when x = 1 then y else 0 end) as ths,
max(case when x = 2 then y else 0 end) as fivhun,
max(case when x = 3 then y else 0 end) as hund,
max(case when x = 4 then y else 0 end) as fif,
max(case when x = 5 then y else 0 end) as twenty,
max(case when x = 6 then y else 0 end) as tens,
max(case when x = 7 then y else 0 end) as fives,
max(case when x = 8 then y else 0 end) as twos,
max(case when x = 9 then y else 0 end) as ones
from r
group by bt, cno, amt
order by bt, cno;
t
共通テーブル式 (CTE) は、1 ~ 9 の数字を生成するダミー テーブルを使用して実際のデータをクロス結合し、後で使用するために各レベルに請求額の値 (Robert Co が正しいと仮定) を割り当てます。
CTE は再帰的で、r
11gR2 からしか機能しないと思います。ユニオンの最初の部分は、請求書がこれまでに合計したものの「実行中の合計」を確立します。これは、再帰の最初のステップであるためゼロです。x
再帰結合に使用されるダミーのゼロ値を除いて、残りの列は使用されません。和集合の 2 番目の部分は、このレベルから前のレベルの現在の合計を減算し、amt
その額面の紙幣全体の数 (実際に報告したいもの) を見つけ、その数値を含めるために現在の合計を再計算します。ループを一巡するたびに、請求書のサイズが減少し、現在の合計が増加します。
したがって、これは多くの行になり、各請求書の数量が異なる行になります。適切な列の下に値を表示するには、ピボットする必要があります。それが、最後のmax()
andgroup by
ビットが行うことです。
私のダミーデータの場合、同じ結果が得られます。
BT CNO AMT THS FIVHUN HUND FIF TWENTY TENS FIVES TWOS ONES
--- --- ---------------- ------- ------ ---- --- ------ ---- ----- ---- ----
1 2 123,456,789 123456 1 2 1 1 1 1 2 0
3 4 87,654,321 87654 0 3 0 1 0 0 0 1
5 6 1,234,567 1234 1 0 1 0 1 1 1 0
ちなみに、私は最初にmod()
(AndriyMが示唆するように)これを単純化しようとしましたが、各値を個別に計算することはできません:
select bt, cno, amt,
floor( amt/1000) as ths,
floor(mod(amt, 1000)/ 500) as fivhun,
floor(mod(amt, 500)/ 100) as hund,
floor(mod(amt, 100)/ 50) as fif,
floor(mod(amt, 50)/ 20) as twenty,
floor(mod(amt, 20)/ 10) as tens,
floor(mod(amt, 10)/ 5) as fives,
floor(mod(amt, 5)/ 2) as twos,
floor(mod(amt, 2)/ 1) as ones
from employer
order by bt, cno;
BT CNO AMT THS FIVHUN HUND FIF TWENTY TENS FIVES TWOS ONES
--- --- ---------------- ------- ------ ---- --- ------ ---- ----- ---- ----
1 2 123,456,789 123456 1 2 1 1 0 1 2 1
3 4 87,654,321 87654 0 3 0 1 0 0 0 1
5 6 1,234,567 1234 1 0 1 0 0 1 1 1
ほとんどの値は同じですが、tens
は all0
で、ones
は all1
です。後者は簡単に説明できますが、なぜすべてが1
. fives
値が である場合、1
分割する残りの金額は偶数になるため、 である必要ones
があります0
。同様に、tens
値はfif
考慮されていません。そのため、このような単純なクエリでは処理できない値の間に依存関係があります。問題の列を微調整して、それを考慮に入れることもできますが、もちろん、微妙な間違いが発生するリスクがあります。