(業務でコピペ利用するための、ほとんど個人的なメモ。)
例
* Sample Data ;
data DT1;
input NO:$3. SEX:$1. AGE:8.;
cards;
001 F 39
002 M 25
;
NO・・・顧客ID
SEX・・・性別
AGE・・・年齢
data DT2;
input NO:$3. FOOD:$10. BUYDATE:yymmdd10.;
format BUYDATE yymmdd10.;
cards;
001 ORANGE 2017/12/11
001 APPLE 2017/12/13
001 CHERRY 2017/12/10
002 ORANGE 2017/12/15
002 APPLE 2017/12/05
;
NO・・・顧客ID
FOOD・・・購入食品
BUYDATE・・・購入日
|
上のデータから、顧客ID毎に購入日の最小値を取得したいとします。
data OUT;
set DT1;
/* 購入データをHashオブジェクトに格納 */
if _n_=1 then do;
length BUYDATE 8.;
call missing( BUYDATE );
dcl hash buy( dataset:"DT2", multidata:"y" );
buy.definekey("NO");
buy.definedata("BUYDATE");
buy.definedone();
end;
/* Hashオブジェクト内をループして、顧客IDごとの購入日の最小値を取得 */
rc = buy.find();
if rc = 0 then MINDATE = BUYDATE;
do while (rc = 0);
rc = buy.find_next();
if rc = 0 then MINDATE = min( MINDATE, BUYDATE );
end;
format MINDATE yymmdd10.;
keep NO SEX AGE MINDATE;
run;
|
解説
Hashの触りとして以下記事を読むと理解しやすいです。
http://sas-boubi.blogspot.jp/2015/02/hash.html
(SAS忘備録:Hashオブジェクトを使おう)
今回やってる事は、データステップ100万回で解説されてる事なので、以下記事を見て頂くと分かると思います。
http://sas-tumesas.blogspot.jp/2014/07/key-multidata-findnext.html
(データステップ100万回:ハッシュオブジェクトの世界⑧ keyの重複を許容する multidata find_nextメソッド)
かいつまんで解説
dcl hash buy( dataset:"DT2", multidata:"y" );
buy.definekey("NO");
buy.definedata("BUYDATE");
buy.definedone();
|
まずはHashオブジェクトの定義から。
データセットDT2をHashオブジェクトに格納し、「multidata:'y'」で、Key値の重複を許しています。
変数NOをKey値、変数BUYDATEをKey値に関連づける変数として定義しています。
rc = buy.find();
if rc = 0 then MINDATE = BUYDATE;
|
findメソッドでHashオブジェクト内をKey値で検索。
該当するKey値があったら、取得したBUYDATEをMINDATEに格納。
do while (rc = 0);
rc = buy.find_next();
if rc = 0 then MINDATE = min( MINDATE, BUYDATE );
end;
|
find_nextメソッドで、Hashオブジェクト内の次のレコードを検索。
該当するKey値があったら、取得したBUYDATEをMINDATEと比較し、最小日付をMINDATEに格納。
これをHashオブジェクト内に該当するレコードがなくなるまで、do whileでループしています。
一応今回やってることは、SQLやMEANSとかの方が楽に求められるけど、DATAステップ内で完結できるのが最大のメリットだと思います。
📝注意
記事の中で使用している「_N_」は「サブセット化IF」と一緒に使用すると正しく動かなくなりやすいです。