proc sqlの第5回目です。今回はテーブルの結合についてです。SQLはデータステップのmergeステートメントよりも多様な結合を実行することができます。
横結合
横結合は2つのテーブルを結合条件に基づいて横に結合することです。データステップのmergeステートメントと同等の操作となります。
ただし両方のテーブルに同じ名前のカラムが存在する場合はエラーとなります。データステップですと最後に指定したデータセット由来の変数で上書きされてしますので注意が必要ですが、
SQLではそのような心配はありません。
構文は以下の通りです。
proc sql;
select < table1 >.column1,....
from < table1 > < right | left | inner | full |cross > join < table2 >
on < table1 >.key = < table2 > .key2;
*cross joinならwhereステートメント;
quit;
joinステートメントで結合したいテーブルを指定し、onステートメントで結合条件を指定します。
これだとわかりにくいので、以下のテーブルを利用して実際の実行結果を見てみましょう。
(DS1)
Obs | id | name | department |
---|---|---|---|
1 | 1 | Kyoko | sales |
2 | 2 | Kanna | sales |
3 | 3 | Rei | HR |
4 | 4 | Aska | HR |
5 | 5 | Shinji | Engineering |
(DS2)
Obs | id2 | name | age |
---|---|---|---|
1 | 3 | Rei | 14 |
2 | 4 | Aska | 15 |
3 | 5 | Shinji | 16 |
4 | 6 | Misato | 28 |
5 | 7 | Ryoji | 29 |
左結合
横結合を実行して、ds1に存在する従業員の年齢をds2から取得します。結合にはカラムidとid2をキーとして指定します。
データステップと異なりキーの名前が一致している必要はありません。この点はデータステップよりも便利です。
proc sql noprint;
create table ds3 as
select ds1.*,
ds2.age
from ds1 left join ds2
on ds1.id=ds2.id2;
quit;
上記のコードを実行するとこうなります。
Obs | id | name | department | age |
---|---|---|---|---|
1 | 1 | Kyoko | sales | . |
2 | 2 | Kanna | sales | . |
3 | 3 | Rei | HR | 14 |
4 | 4 | Aska | HR | 15 |
5 | 5 | Shinji | Engineering | 16 |
left joinだと joinステートメントの左側で指定したテーブル(ここではds1)に存在するレコードのみが保持されるため、MisatoとRyoji由来のデータはテーブルds3には存在しません。
右結合
同じテーブルを使って右結合を実行します。
proc sql noprint;
create table ds3 as
select ds1.*,
ds2.age
from ds1 right join ds2
on ds1.id=ds2.id2;
quit;
この場合ですと joinステートメントの右側で指定したテーブル(ここではds2)に存在するレコードのみが保持されます。
そのためds1にしか存在しないKyokoとKanna由来のデータは出力されませんでした。
Obs | id | name | department | age |
---|---|---|---|---|
1 | 3 | Rei | HR | 14 |
2 | 4 | Aska | HR | 15 |
3 | 5 | Shinji | Engineering | 16 |
4 | . | 28 | ||
5 | . | 29 |
内部結合
内部結合(inner join) は両方のテーブルに存在するレコードのみが出力されます。
Rei, Aska, Shinjiはds1, ds2の両方にデータが存在するため、この3名のみが出力されます。いわゆる論理積というやつですね。
proc sql noprint;
create table ds3 as
select ds1.*,
ds2.age
from ds1 inner join ds2
on ds1.id=ds2.id2;
quit;
Obs | id | name | department | age |
---|---|---|---|---|
1 | 3 | Rei | HR | 14 |
2 | 4 | Aska | HR | 15 |
3 | 5 | Shinji | Engineering | 16 |
外部結合
外部結合(full join) はいずれかのテーブルに存在するレコードが出力されます。論理和というやつです。
proc sql noprint;
create table ds3 as
select ds1.*,
ds2.age
from ds1 full join ds2
on ds1.id=ds2.id2;
quit;
Obs | id | name | department | age |
---|---|---|---|---|
1 | 1 | Kyoko | sales | . |
2 | 2 | Kanna | sales | . |
3 | 3 | Rei | HR | 14 |
4 | 4 | Aska | HR | 15 |
5 | 5 | Shinji | Engineering | 16 |
6 | . | 28 | ||
7 | . | 29 |
SQLを使うメリット
mergeステートメントにはないメリットは以下の通りです。
- 結合時に変数の上書きされる心配がない。
- キー変数が異なっていても結合できる。
- 交差結合(cross join)が結合できる。
とくに変数の上書きの問題点がない点は有用だと思います。この問題は度々作業のやり直しの原因になることがあったりするので。
交差結合はたまーに使いますね。
実務ではleftとinnerが頻出かと思います。