トップページに戻る
次のSQLパズルへ
前のSQLパズルへ
10-326 最小上界な行がなければ、最大下界を取得その2
SQLパズル
NameT
ID DateCol Val
--- ---------- ----
111 2010-03-13 John
111 2010-03-17 Smith
222 2010-03-12 Tom
222 2010-03-18 Jane
TranT
ID DateCol
--- ----------
111 2010-01-06
111 2010-03-12
111 2010-03-16
111 2010-03-20
111 2010-03-25
111 2010-04-20
222 2010-01-16
222 2010-03-12
222 2010-03-16
222 2010-04-20
NameTからValを取得したTranTを表示する。
取得するValは、同じIDでDateColをソートキーとしての、NameTの最小上界のValとする。
もし存在しなければ、同じIDでDateColをソートキーとしての、NameTの最大下界のValとする。
出力結果
ID DateCol Val
--- -------- -----
111 10-01-16 John
111 10-03-12 John
111 10-03-16 Smith
111 10-03-20 Smith
111 10-03-25 Smith
111 10-04-20 Smith
222 10-01-16 Tom
222 10-03-12 Tom
222 10-03-16 Jane
222 10-04-20 Jane
データ作成スクリプト
create table NameT(ID,DateCol,Val) as
select 111,date '2010-03-13','John' from dual union all
select 111,date '2010-03-17','Smith' from dual union all
select 222,date '2010-03-12','Tom' from dual union all
select 222,date '2010-03-18','Jane' from dual;
create table TranT(ID,DateCol) as
select 111,date '2010-01-06' from dual union all
select 111,date '2010-03-12' from dual union all
select 111,date '2010-03-16' from dual union all
select 111,date '2010-03-20' from dual union all
select 111,date '2010-03-25' from dual union all
select 111,date '2010-04-20' from dual union all
select 222,date '2010-01-16' from dual union all
select 222,date '2010-03-12' from dual union all
select 222,date '2010-03-16' from dual union all
select 222,date '2010-04-20' from dual;
SQL
--■■■相関サブクエリを使う方法■■■
select ID,DateCol,
(select
case max(case when b.DateCol >= a.DateCol then 1 else 0 end)
when 1 then max(b.Val) Keep(Dense_Rank First order by case when b.DateCol >= a.DateCol
then 0 else 1 end,b.DateCol)
else max(b.Val) Keep(Dense_Rank Last order by b.DateCol) end
from NameT b
where b.ID = a.ID) as Val
from TranT a
order by ID,DateCol;
--■■■内部結合を使う方法■■■
select ID,DateCol,Val
from (select a.ID,a.DateCol,b.Val,
Row_Number() over(partition by a.ID,a.DateCol
order by b.DateCol) as rn
from TranT a
Join (select DateCol,Val,ID,
max(DateCol) over(partition by ID) as maxData
from NameT) b
on a.ID = b.ID
and (a.DateCol <= b.DateCol or b.DateCol=b.maxData))
where rn=1
order by ID,DateCol;
解説
相関サブクエリは、分かりやすいのですが、
分析関数を使ってから内部結合したほうが、パフォーマンスが良さそうですねぇ