トップページに戻る
次のSQLパズルへ
前のSQLパズルへ
10-302 Partitioned Outer Joinして分析関数
SQLパズル
w_acctテーブル
acct vers
---- ----
A1 0
A2 0
A3 0
A1 1
A2 1
A1 2
A4 2
versの昇順でacctの履歴ログを下記の形で出力する。
・LD列
NO_CHANGEならacctの値、NO_CHANGEでなければnull
・ADD_REMOVE列
新規なら、NEW
2回目の登場なら、NO_CHANGE
消えたら、REMOVED
出力結果
acct vers LD ADD_REMOVE
---- ---- ---- ----------
A1 0 null NEW
A2 0 null NEW
A3 0 null NEW
A1 1 A1 NO_CHANGE
A2 1 A2 NO_CHANGE
A3 1 null REMOVED
A1 2 A1 NO_CHANGE
A2 2 null REMOVED
A4 2 null NEW
データ作成スクリプト
create table w_acct as
select 'A1' acct,0 vers from dual union all
select 'A2' acct,0 vers from dual union all
select 'A3' acct,0 vers from dual union all
select 'A1' acct,1 vers from dual union all
select 'A2' acct,1 vers from dual union all
select 'A1' acct,2 vers from dual union all
select 'A4' acct,2 vers from dual;
SQL
--■■■Partitioned Outer Joinを使う方法(10g以降)■■■
select acct,vers,
case when appearCnt=1 and preCnt = 0 then 'null'
when appearCnt=preCnt then 'null'
else acct end as LD,
case when appearCnt=1 and preCnt = 0 then 'NEW'
when appearCnt=preCnt then 'REMOVED'
else 'NO_CHANGE' end as ADD_REMOVE
from (select a.acct,b.vers,
count(b.acct)
over(partition by a.acct order by b.vers) as appearCnt,
count(b.acct)
over(partition by a.acct
order by b.vers rows between unbounded preceding
and 1 preceding) as preCnt,
Lag(b.acct) over(partition by a.acct order by b.vers) as LagVal
from (select distinct acct from w_acct) a
Left Join w_acct b
partition by (b.vers)
on a.acct = b.acct)
where appearCnt > preCnt
or LagVal is not null
order by vers,acct;
--■■■Partitioned Outer Joinを使わない方法■■■
select acct,vers,
case when appearCnt=1 and preCnt = 0 then 'null'
when appearCnt=preCnt then 'null'
else acct end as LD,
case when appearCnt=1 and preCnt = 0 then 'NEW'
when appearCnt=preCnt then 'REMOVED'
else 'NO_CHANGE' end as ADD_REMOVE
from (select a.acct,b.vers,
count(c.acct)
over(partition by a.acct order by b.vers) as appearCnt,
count(c.acct)
over(partition by a.acct
order by b.vers rows between unbounded preceding
and 1 preceding) as preCnt,
Lag(c.acct) over(partition by a.acct order by b.vers) as LagVal
from (select distinct acct from w_acct) a
cross Join (select distinct vers from w_acct) b
Left Join w_acct c
on a.acct = c.acct
and b.vers = c.vers)
where appearCnt > preCnt
or LagVal is not null
order by vers,acct;
解説