トップページに戻る
次のSQLパズルへ
前のSQLパズルへ
10-308 Lag関数とLead関数のignore nullsを模倣
SQLパズル
emuIgnoNullテーブル
SortKey Val
------- ----
1 2
2 null
5 4
9 null
11 6
12 null
14 null
16 5
17 null
20 3
21 null
22 4
Oracle11gR2で使用できるが、Oracle11gR1で使用できない、
下記の
Lag関数のignore nullsオプションと
Lead関数のignore nullsオプションを使ったSQLと同じ結果を取得する。
select SortKey,Val,
Lag (Val ignore nulls,2) over(order by SortKey) as Lag2,
Lead(Val ignore nulls,2) over(order by SortKey) as Lead2
from emuIgnoNull;
出力結果
SortKey Val Lag2 Lead2
------- ---- ---- -----
1 2 null 6
2 null null 6
5 4 null 5
9 null 2 5
11 6 2 3
12 null 4 3
14 null 4 3
16 5 4 4
17 null 6 4
20 3 6 null
21 null 5 null
22 4 5 null
データ作成スクリプト
create table emuIgnoNull(SortKey,Val) as
select 1, 2 from dual union all
select 2,null from dual union all
select 5, 4 from dual union all
select 9,null from dual union all
select 11, 6 from dual union all
select 12,null from dual union all
select 14,null from dual union all
select 16, 5 from dual union all
select 17,null from dual union all
select 20, 3 from dual union all
select 21,null from dual union all
select 22, 4 from dual;
SQL
--■■■First_Value関数およびLast_Value関数でignore nullsを使う方法■■■
select SortKey,Val,
case when aboveCnt >= 2
then First_Value(Lag2 ignore nulls)
over(order by SortKey rows between current row
and Unbounded Following)
end as Lag2,
case when belowCnt >= 2
then Last_Value(Lead2 ignore nulls)
over(order by SortKey)
end as Lead2
from (select SortKey,Val,
case when Val is not null
then Lag (Val,2,null)
over(partition by nvl2(Val,0,1) order by SortKey) end as Lag2,
count(Val) over(order by SortKey rows between unbounded preceding
and 1 preceding) aboveCnt,
case when Val is not null
then Lead(Val,2,null)
over(partition by nvl2(Val,0,1) order by SortKey) end as Lead2,
count(Val) over(order by SortKey rows between 1 following
and unbounded following) belowCnt
from emuIgnoNull)
order by SortKey;
--■■■rangeスキャンを使う方法■■■
select SortKey,Val,
max(Val) over(order by aboveCnt range between 2 preceding
and 2 preceding) as Lag2,
max(Val) over(order by belowCnt range between 2 preceding
and 2 preceding) as Lead2
from (select SortKey,Val,
count(Val) over(order by SortKey rows between unbounded preceding
and 1 preceding) aboveCnt,
count(Val) over(order by SortKey rows between 1 following
and unbounded following) belowCnt
from emuIgnoNull)
order by SortKey;
解説
rangeスキャンを使う方法が分かりやすいでしょう。