初めに

今回はDataステップで行えるMergeステートメントについて説明します。
Mergeステートメントは名前の通り、結合処理、つまり複数のデータセットを(横)結合するものです。
役割としては、SQLのjoin句と同じ位置付けのものですが、n 対 m の結合の際、挙動がSQLと異なるので注意が必要です。
n 対 m 含め、Mergeステートメントの概要から順に説明していきます。
※ちなみに、SASでの結合処理は、上記と別に「Proc SQL」という”SASでSQLが使用できる”Procステップがあります。

「Mergeステートメント」の枠組み

上記の通り、「複数データセットを(横)結合」をするためのものです。
下記の枠組みでコードを書くものです。
mergeステートメントに結合対象のデータセットを記述し、byステートメントに結合キーを記述します。
次に「(in=in1)」について説明します。
下記コードでは「table_1(in=in1)」という形で記述されています。
これは、「”出力データにて、table_1に存在するデータならば「1」を設定というフラグ変数「in1」を作成する」形になります。
前提として、mergeステートメントは所謂”完全外部結合”の形で結合されます。
なので、例えば、”table_1をベースにtable_2を結合“をしたい場合は、下記コードのように、”上記フラグ変数とif文を用いて“、不要なオブザベーションを除外します。

※注意点が一つあります。Mergeステートメントを使用する際、結合対象のデータセット全てが、結合キーでソート済みである必要があります。(そうでないと、エラーが発生します。)なので、ソート済みでない場合は、結合前に「proc sort」等でソートをしましょう。

data merge_data;
merge table_1(in=in1) table_2;
by key_id;
if in1=1 then output;
run;

結合 (1 対 n)

それでは、実際に結合処理をしてみましょう。
ここに部署マスタと社員マスタがあります。
社員マスタには部署ID(dept_id)はありますが、部署名(dept_name)がありません。
社員マスタと部署マスタを結合して、社員マスタに部署名を付与しましょう。

[データ]

dept_iddept_name
1account
2sales
3legal
4market
部署マスタ(dept_mst)
emp_idemp_namedept_id
100sasaki2
200tanaka1
300yoshida1
400okada3
500nishino2
社員マスタ(employee_mst)

[求める出力結果]

emp_idemp_namedept_iddept_name
100sasaki2sales
200tanaka1account
300yoshida1account
400okada3legal
500nishino2sales
結合結果(merge_data)

今回のポイントは下記です。

  • 社員マスタに紐づかない部署マスタのデータを削除する。
  • 結合前に、社員マスタを部署ID(結合キー)でソートをする必要がある。

上記ポイントを考慮した下記コードで求める結果が得られます。

/* 社員マスタを部署ID(結合キー)でソート */
proc sort data=employee_mst;
by dept_id;
run;

/* 結合 */
data merge_data;
merge employee_mst(in=emp) dept_mst;
by dept_id;
/* 社員マスタに紐づかない部署マスタのデータを削除 */
if emp=1 then output;
run;

如何でしょうか。
SQLを使っている方でしたら、指定する内容(データセット・キー)や結果が同じなので、理解しやすいと思います。
次は、 n 対 m の説明をします。
頭出ししましたが、n 対 m の場合はSQLと結果が異なるので(特にSQLを使っている方は)要注意です。

結合 (n 対 m)

概要

SAS (Mergeステートメント) で、n 対 m の結合を行うと、結論としては下記の通りになります。

[(下記結論の) 前提]

  • n >= m とする。
  • 1つのキー値について、n 対 m の結合結果を説明する。
  • データセット名について、n 側を table_1 、m側を table_2 とする。
  • キー以外変数について、n 側を var_1 、m側を var_2 とする。

[結論 (結合結果)]

  1. オブザベーション数は n になる。 ※SQLの場合は n × m 行。
  2. var_1 , var_2 の値は、”結合時の入力データセットにおける並び順でそのまま結合した形”になる。(例えば、結合結果1行目の値は、各入力データセットの1行目の値になる。) ※SQLの場合はデカルト積。
  3. 上記2.の通り、”結合して余った (n-m) 個のオブザベーション(table_1側)”に紐付くvar_2の値は、”table_2の末行におけるvar_2の値”になる。

実際に結合してみます。
上記結論の通りになることが確認できます。

入出力データセット
入力
idstr_a
1a_1_1
1a_1_2
1a_1_3
2a_2_1
2a_2_2
data_a
idstr_b
1b_1_1
1b_1_2
2b_2_1
2b_2_2
2b_2_3
data_b
出力 (結合結果)
idstr_astr_b
1a_1_1b_1_1
1a_1_2b_1_2
1a_1_3b_1_2
2a_2_1b_2_1
2a_2_2b_2_2
2a_2_2b_2_3
merge_data
コード
/* 入力データセット(data_a) */
data data_a;
infile datalines delimiter=',';
input 
	id
	str_a $ 
    ;
cards;
1 , a_1_1
1 , a_1_2
1 , a_1_3
2 , a_2_1
2 , a_2_2
;
run;

/* 入力データセット(data_b) */
data data_b;
infile datalines delimiter=',';
input 
	id
	str_b $ 
    ;
cards;
1 , b_1_1
1 , b_1_2
2 , b_2_1
2 , b_2_2
2 , b_2_3
;
run;

/* 結合 */
data merge_data;
merge data_a data_b;
by id;
run;

最後に

SASを使い始めた方は、既にSQLを使っている(or 知っている)方が多いと思います。
上記で説明した通り、Mergeステートメントを使用する際は、n 対 m になるのか注意が必要です。
n 対 m の結合をSQLと同様に行いたいときは、「Proc SQL」を使いましょう。

By clear

データエンジニア・機械学習・分析等を主とし、Webアプリ開発も行っているフリーランスです。