The Nameless City

何故か製薬やSAS関連のブログ、の予定。

SASマクロプログラムの要諦

ネット見てると、SASプログラマーも数えるほどだけどそれなりにいるという事で、昔に比べて色々あるんだけど。

SASマクロ関数でのクォート処理は面倒な部類に入るのでマクロ言語でやるよりdataステップでマクロ変数を読み込む方法とかを使う方が幸せになれますよ、という話。

データステップ100万回      SAS新手一生: シングルコーテーション内のマクロ変数を展開する
SASマクロをウンザリするほど使ってきたが、未だにクォート処理周りは困る事がある。
クォート処理は、SASの内部では特殊な文字を割り当てられている事があり、それがSASマクロ変数展開時に解除されてない為に、SASマクロ変数を使った文字列の結合なんかで困ったりすることがある。


というか、クォート処理みたいなのをSASマクロのプレコンパイルの所で処理してしまうのは、使い勝手の点で問題があるので、最近自分の場合には大抵こうしてる。

%let M=いろは;

data A;
X=%unquote(%bquote('&M'));
run;

%let M=いろは;

data A;
X=symget('M');
run;

同様に、最近は%sysfuncとか殆ど使わなくなった。%sysfunc(exist(~))は別口だけど。
SASマクロのプレコンパイル領域では使える関数がマニアックになりがちなのと、debugが難しくなりがちという欠点があるので、dataステップでやると楽。


自分は、この手の問題では、しばしば、data _null_を使う。
例えば、データセットのOBS数を取り出すのに、

%let _N_OBS = 0 ;
data _null_ ;
if 0 then set DS NOBS=_N_OBS ;
cal symputx('_N_OBS',_N_OBS) ;
stop ;
run ;
%put &_N_OBS. ;

とか、

%let _TIMESTAMP = ;
data _null_ ;
_TMP = put(datetime(),E8601DT.) ;
_TMP = tranwrd(_TMP,"-","") ;
_TMP = tranwrd(_TMP,"T","") ;
_TMP = tranwrd(_TMP,":","") ;
call symputx('_TIMESTAMP',) ;
run ;
%put &_TIMESTAMP. ;

とか。

インライン型のマクロを作らない方が幸せになれる。

%macro Inf( Ds=, Var=Name, Row=11 );
data _null_;
set &Ds(firstobs=&Row obs=&Row);
call symputx('MVar', &Var);
run;
%mend;

%Inf( Ds=Sashelp.Class, Var=Name, Row=11 );
%put &MVar;

とすれば、指定データセットDs・変数Varの第Row行目の値をマクロ変数MVarに代入することができます(MVar=ジョイス)。

そこで、

%let MVar=%Inf( Ds=Sashelp.Class, Var=Name, Row=11 );

としたときに、MVarがジョイスとなるようなマクロ%infは多分できないと思いますが、可能でしたらお教えください。

SASプログラミング掲示板(データステップ100万回)|指定行・変数のマクロ化|トピック表示 > スレッドNo.16

回答者が、RC関数とか使っているが、バグってclose関数呼ばれないと大変面倒臭い事になるのでRC関数とかは全然オススメしない。
インライン型のマクロ関数というのは、結構、エラーになった時に何になるか分からないSASマクロの更に深みにハマる事があるので、そんな事するぐらいなら、素直に構造自体を内部に入れて、普通のマクロにした方が幸せになれる。大抵。時々セミコロン抜けたりするし。

%macro Inf( Ds=, Var=Name, Row=11, Mvar=Mvar);
data _null_;
set &Ds(firstobs=&Row obs=&Row);
call symputx(symget('Mvar'), &Var,'G');
run;
%mend;

%Inf( Ds=Sashelp.Class, Var=Name, Row=11, Mvar=Mvar );

グローバルスコープでのマクロ変数に格納する形になってしまっているが、予めMvarを宣言して格納させる形にするとかなら、逆にマクロ変数がない場合には実行しないようにする方法もある。
ここらへんの「できたらいい」話ってのは結局の所あんまり凝っても仕方ないが。

似たような話で、call executeは最近あんま使ってない。

WORKライブラリの中にSASプログラムファイルを吐き出して%includeして使うとかそんな事をよくしてる。デバッグ楽だし。