トップページに戻る    次のSQLパズルへ    前のSQLパズルへ

3-2 別テーブル優先の抽出

SQLパズル

マスタテーブル
Col1  Col2      Col3
----  --------  ------------
1     吉法師    尾張のうつけ
2     日吉      日輪の子
3     竹千代    今川の人質

優先テーブル
Col1  Col2      Col3
----  --------  ------
1     織田信長  右大臣
3     徳川家康  内府
4     明智光秀  日向守

マスタテーブルのCol1,Col2,Col3を取得する
ただし、マスタテーブルのCol1に紐づくレコードが優先テーブルに存在すれば
優先テーブルのCol1,Col2,Col3を取得する。

マスタテーブル、優先テーブルのプライマリキーは、Col1とする。

出力結果
Col1  Col2      Col3
----  --------  ------
1     織田信長  右大臣
2     日吉      日輪の子
3     徳川家康  内府


データ作成スクリプト

create table マスタテーブル(
Col1 number,
Col2 varchar2(8),
Col3 varchar2(12),
primary key(Col1));

create table 優先テーブル(
Col1 number,
Col2 varchar2(8),
Col3 varchar2(12),
primary key(Col1));

insert into マスタテーブル values(1,'吉法師','尾張のうつけ');
insert into マスタテーブル values(2,'日吉','日輪の子');
insert into マスタテーブル values(3,'竹千代','今川の人質');
insert into 優先テーブル values(1,'織田信長','右大臣');
insert into 優先テーブル values(3,'徳川家康','内府');
insert into 優先テーブル values(4,'明智光秀','日向守');
commit;


SQL

--■■■nvl2関数で分岐させる方法■■■
select
a.Col1,
nvl2(b.Col1,b.Col2,a.Col2) as Col2,
nvl2(b.Col1,b.Col3,a.Col3) as Col3
from マスタテーブル a,優先テーブル b
where a.Col1=b.Col1(+)
order by Col1;

--■■■decode関数で分岐させる方法■■■
select
decode((select count(b.Col1) from 優先テーブル b where b.Col1=a.Col1),1,
              (select b.Col1 from 優先テーブル b where b.Col1=a.Col1),Col1) as Col1,
decode((select count(b.Col1) from 優先テーブル b where b.Col1=a.Col1),1,
              (select b.Col2 from 優先テーブル b where b.Col1=a.Col1),Col2) as Col2,
decode((select count(b.Col1) from 優先テーブル b where b.Col1=a.Col1),1,
              (select b.Col3 from 優先テーブル b where b.Col1=a.Col1),Col3) as Col3
from マスタテーブル a
order by Col1;

--■■■case when existsで分岐させる方法■■■
select
case when exists(select 1 from 優先テーブル b where b.Col1=a.Col1)
     then  (select b.Col1 from 優先テーブル b where b.Col1=a.Col1)
     else Col1 end as Col1,
case when exists(select 1 from 優先テーブル b where b.Col1=a.Col1)
     then  (select b.Col2 from 優先テーブル b where b.Col1=a.Col1)
     else Col2 end as Col2,
case when exists(select 1 from 優先テーブル b where b.Col1=a.Col1)
     then  (select b.Col3 from 優先テーブル b where b.Col1=a.Col1)
     else Col3 end as Col3
from マスタテーブル a
order by Col1;

--■■■unionを使用する方法■■■
select Col1,Col2,Col3 from マスタテーブル a
where not exists(select 1 from 優先テーブル b
                  where b.Col1=a.Col1)
union all select Col1,Col2,Col3 from 優先テーブル b
where exists(select 1 from マスタテーブル a
              where b.Col1=a.Col1)
order by Col1;


解説

外部結合してnvl2関数で分岐させる方法や、
decode関数で分岐させる方法、case when existsで分岐させる方法がありますが、
unionを使用する方法もあります。

unionを使用する方法では、
マスタテーブルのCol1に紐づくレコードが優先テーブルに存在しなければ、最初のselect文が行を返し
マスタテーブルのCol1に紐づくレコードが優先テーブルに存在すれば、次のselect文が行を返す
クエリになっていて、
ブール代数の補元法則
 A + not(A) = 1
を使用してます。