MERGE:8つの方法

Merging Data Eight Different Waysより

データセットをマージする8つの方法が紹介されています。
以下のPATDATAとADVERSEの2つのデータセットをSUBJECTでマージし、
かつADVERSEのみ存在するデータを残したものをALLDATA0に格納するやり方を
例としています。

Dataset: PATDATA
	SUBJECT TRT_CODE
	124263 A
	124264 A
	124265 B
	124266 B
	
Dataset: ADVERSE
	SUBJECT EVENT
	124263 HEADACHE
	124266 FEVER
	124266 NAUSEA
	124267 FRACTURE

方法(1)DATAステップ内でMEREGEを使う方法。
一番ポピュラーなやりかたですね。

DATA alldata0;
	MERGE adverse (in=a)
	patdata (in=b);
	BY subject;
	IF a;
RUN;

(2)PROC SQLでJOIN句で連結する方法です。

PROC SQL;
	CREATE TABLE alldata0 AS
		SELECT a.*, b.trt_code
		FROM adverse a
		LEFT JOIN
		patdata b
		ON a.subject=b.subject;
	QUIT;
RUN;

(3)SETステートメントでKEYオプションを使う方法。
こんなやり方もあったんですね。知りませんでした。

DATA alldata0;
	SET adverse;
	SET patdata KEY=subject /UNIQUE;
	DO;
		IF _IORC_ THEN DO;
			_ERROR_=0;
			trt_code='';
		END;
	END;
RUN;

(4)PATDATAから文字フォーマットを作り出して、それをADVERSEデータセットに当てる方法。

DATA fmt;
	RETAIN fmtname 'TRT_FMT' type 'C';
	SET patdata;
	RENAME subject=start trt_code=label;
RUN;

PROC FORMAT CNTLIN=fmt;
RUN;

DATA alldata0;
	SET adverse;
	ATTRIB trt_code LENGTH=$1 LABEL='Treatment Code';
	trt_code=PUT(subject,$trt_fmt.);
RUN;

(5)PATDATAからハッシュテーブルを作って、ADVERSEデータセットにヒット差せる方法。
ただしSAS9.1以降でないとできないそうです。

DATA alldata0;
	IF _n_=0 THEN SET patdata;
	IF _n_=1 THEN DO;
	DECLARE HASH _h1
		(dataset: "PATDATA");
		rc=_h1.definekey("SUBJECT");
		rc=_h1.definedata("TRT_CODE");
		rc=_h1.definedone();
		call missing(SUBJECT,TRT_CODE);
	END;
	SET adverse;
	rc=_h1.find();
	IF rc^=0 THEN trt_code=" ";
	DROP rc;;
RUN;

(6)配列を使う方法。
ここまでするんだったら、個人的には普通にMERGEかPROC SQLを使った方が良い気がしますけど・・・

DATA _null_;
	SET sashelp.vtable;
	WHERE libname='WORK';
	WHERE ALSO memname in('PATDATA','ADVERSE');
	CALL SYMPUT('X'||memname,put(nobs,8.));
RUN;

DATA alldata0;
	LENGTH trt_code $1;
	ARRAY f{&xpatdata.,2} $6 _TEMPORARY_;
	DO i=1 TO &xpatdata.;
		SET patdata (RENAME=(trt_code=trt_code_dict));
		f{i,1}=PUT(subject,6.);
		f{i,2}=trt_code_dict;
	END;
	DO i=1 TO &xadverse.;
		SET adverse;
		trt_code='';
		DO j=1 TO &xpatdata.;
			IF subject=INPUT(f(j,1),best.) THEN DO;
				trt_code=f{j,2};
				OUTPUT;
			END;
			IF ^MISSING(trt_code) THEN LEAVE;
		END;
		IF MISSING(trt_code) THEN OUTPUT;
	END;
	DROP i j trt_code_dict;
RUN;

(7)MODIFYステートメントを使う方法
なんだかかえって何をしているのかわかりづらくなってしまう気がします。

DATA adverse;
	DO p = 1 TO totobs;
		_IORC_ = 0;
		SET patdata POINT=p NOBS=totobs;
		DO WHILE(_IORC_=%SYSRC(_SOK));
			MODIFY adverse KEY=subject;
			SELECT (_IORC_);
				WHEN (%SYSRC(_SOK)) DO; /*MATCH FOUND*/
					SET patdata POINT=p; trtc=trtcode; REPLACE;
				END;
				WHEN (%SYSRC(_DSENOM)) _ERROR_ = 0; /*NO MATCH FOUND*/
				END;
				OTHERWISE DO; /*A MAJOR PROBLEM SOMEWHERE*/
					PUT 'ERROR: _IORC_ = ' _IORC_ / 'PROGRAM HALTED.';
					_ERROR_ = 0; STOP;
				END;
			END;
		END;
	END;
	STOP;
RUN;

(8)最後はCALL EXECUTEを使う方法

DATA _null_;
	SET patdata;
	CALL EXECUTE("DATA alldat;"||
	" SET adverse;"||
	" WHERE subject='"||STRIP(subject)||"';"||
	" trt_code='"||STRIP(trt_code)||"';"||
	"PROC APPEND BASE=alldata0 DATA=dat0 FORCE;"||
	"RUN;");;
RUN;