【SAS】SQL入門 (結合編)

SQL Procedureを使ったデータセットの結合について紹介します。

スポンサーリンク

使用するサンプルデータ

AとBの2つのデータセットを使います。
それぞれ4レコードずつですが、ID番号3と4は重複していることに注意してください。
また、Aは2018年に、Bは2019年に記録されたデータを想定します。

サンプルデータA, B

data A;
input id sex $ age;
datalines;
1  M  20
2  F  30
3  M  40
4  F  50
run;

data B;
input id sex $ age;
datalines;
3  M  40
4  F  50
5  F  60
6  F  70
run;

title "A (year=2018)";
proc print data=A; run;

title "B (year=2019)";
proc print data=B; run;
title;

実行結果です。

列(縦)方向の結合(Combining)

列方向の結合はUNION句を使います。

UNION

UNIONを使ってデータセット同士を列方向に結合することができます。
構文はデータセットとデータセットをUNIONで繋いであげるだけです。

UNION

/* データセット UNION データセット */
select * from A union select * from B;

ただし、UNIONを使う際に注意しないといけないのは、重複したレコードは結合時に除外されてしまうことです。
重複したレコードを削除せずに結合したい場合は、UNION ALLとすればOKです。

UNION ALL

select * from A union select * from B;
select * from A union all select * from B;

UNIONの仕組みは非常にシンプルで、指定されたデータセット同士をそのまま縦方向に結合します。
UNION以外は通常のSELECT文の使い方と何ら変わりなく使えます。

/* AはID=1だけを結合 */
select * from A where id=1 union select * from B;

/* どのデータセットから追加したかわかるようにラベルを追加 */
select "A" as dsn, 2018 as year, * from A union 
select "B" as dsn, 2019 as year, * from B;

UNIONのエラーチェックは、列ごとにデータ型が一致しているかどうか程度です。
そのため、結合するデータセットの列の数が同じであるか、列順が同じであるかは自身で保証する必要があります。
このことは次のコードで確認できます。

エラーとなる例

/* AとSASHELP.CLASSを結合しようすると、次のようなエラーが返る */
select * from A union all select * from SASHELP.CLASS;
/* ERROR: 列1 (UNIONの第1コントリビュータからの列)は第2コントリビュータからの列とはタイプが異なります。 */

/* 列タイプを揃えるとWARNINGが返るものの実行はできる。 */
select sex,age from A union all select sex,height,weight from SASHELP.CLASS;
/* WARNING: UNION ALLセットの実行により、テーブルをNULL列で拡張しました。 */

1列目について、どちらも文字なのでUNIONは実行されます。
ちなみに、ラベルなど列に関する情報は、列名が一致先に指定したデータセットの情報が優先されます。
ここではAのsexはCHAR(8)、CLASSのsexはCHAR(4)ですが結合後はCHAR(8)となります。

2列目について、AのageとCLASSのheightを結合しようとしています。
実際には全く意味の違う列ですが、データ型が一致しているのでUNIONは実行されます。
逆にいうと、列の位置が違っていたとしても、データ型が一致する限りエラーにならないため注意する必要があります。

3列目は、Aには存在しない列との結合です。
一方が存在しない場合には、存在している列にもとづいて自動的に空白列が生成されます。

行(横)方向の結合(Joining)

列方向の結合はJOIN句を使います。

Left join

Left joinを使った結合は次のように書きます。

Left join

select * from A /* Aに対して、 */
	left join B /* Bを左から結合 */
	on A.id= B.id /* AのIDとBのIDが一致するかを判別 */
;

/* 重複する列を指定する場合は「データセット.列名」で指定 */
select 
	A.id, 
	A.sex as A_sex, /* 同じ名前の列は「as」で別名を指定 */
	B.sex as B_sex, 
	B.age 
from A 
	left join B 
	on A.id= B.id
;

Right join

Right join

select * from A right join B on A.id= B.id;

/* RightをLeftにしてAとBも入れ替えれば、結果は同じ(列の順番は違う) */
select * from B left join A on A.id= B.id;

Inner join

Inner join

select * from A inner join B on A.id= B.id;

/* 次のコードでも同じ結果 */
select * from A, B where A.id= B.id;

Full join

Full join

select * from A full join B on A.id= B.id;

直積

Inner joinで出てきた直積です。実務で使うことはないですが参考までに。

直積

select * from A, B;
スポンサーリンク