2016年6月7日火曜日

「OUTPUT」と「CALL MISSING」のコンボ技


一対多のマージで、一側データ由来の変数値を各BYグループの最初のみに出力したい事ってありませんか?


*** サンプルデータ ;
data DT1;
input A$ B$ C$ @@;
cards;
001 aa cc 002 bb dd
;

A
 B  
 C  
  001    aa     cc   
  002    bb  dd   

data DT2;
input A$ D @@;
cards;
001 11 001 22 001 33 002 44 002 55
;

A
  D  
  001     11   
  001     22
  001     33
  002     44
  002     55


やりたい事

上のデータをMERGEすると、
data OUT1;
  merge DT1 DT2;
  by A;
run;


上記のように一側データ(DT1)由来の黄色部分が繰り返されますが、これを空白にしたい。
A
 B  
 C  
  D  
  001    aa     cc      11   
  001                 22   
  001        33   
  002    bb     dd      44   
  002        55  


前提: 
一対多のマージを前提とします。多対多を含むマージ(一対多対多とか)だと挙動が変わってくるので今回の記事では対象外とします。



方法1 最初に思いつく方法
data OUT1;
  merge DT1 DT2;
  by A;
  if first.A = 0 then call missing( B, C );
run;

以下記事で紹介した「FIRST.BY変数」を利用しています。

1つ注意として、ここで使用している「FIRST.BY変数」は「サブセット化IF」と一緒に使用すると正しく動かなくなりやすいです。



方法2 OUTPUT と CALL MISSING のコンボ技
data OUT1;
  merge DT1 DT2;
  by A;
  output;
  call missing( B, C );
run;

紹介しといてなんですが、方法1の方が、分かり易くていいと思います。
ですが方法2のようなやり方を知ってると、応用がきいて便利な時があります。


方法2の解説

以前の記事 「MERGEステートメントの落とし穴」 で紹介した内容を理解することで、今回の内容も理解がしやすいです。

重要なポイントは、
「一対多のマージにおいて、一側データセットの変数は、BYグループ毎に1回しかPDVに読み込まれない。
(BYグループが変わるまで、PDVに残った値が保持される。。。RETAINのようなイメージ)」


そこで、1オブザベーション毎に
① 「output;」でデータセットOUT1に出力
② 「call missing( B, C );」 でPDVの中の変数BとCを欠損値にする

PDVに残った一側データ由来の変数BとCの値が保持されるのを②によって抑制しているので、BYグループの最初にしかBとCが入らなくなっているわけです。


一側データの変数の数が多い場合は、「call missing( of _all_ );」と書いてしまえば、いっぺんに欠損値に出来るので楽です。

data OUT1;
  merge DT1 DT2;
  by A;
  output;
  call missing( of _all_ );
run;

ただし、PDV内の全変数を欠損値にしているので、
RETAIN等、値を保持するような処理は全て無効になります。


。。。つづく

0 件のコメント:

コメントを投稿