以下の2つのデータセットAを作成するコードを見てください。
data A;
X=1;
run;
data A;
X='1';
run;
変数Xが数値型か文字型か、実行時まで確定しないという状況があるとします。
(proc importやlibname excelとかでexcelを読む場合、型が自動判定なので、
まあよくある話です)
そこで、Xが文字型だったらそのままYに代入し、数値型ならbestフォーマットで
文字型に直してYに代入したいという要望があったとします。
まあ
data B;
length Y $200. ;
set A ;
Y = X;
run;
としちゃえば、Xが文字型だろうと数値型だろうといけますが、当然、数値の場合
「NOTE: 以下の箇所で数値を文字値に変換しました。」がでます。
このNOTEをださないようにするにはどうするか。
やってしまいがちなのが以下のような書き方
data B;
set A;
if vtype(X) = 'C' then Y = X ;
else if vtype(X) = 'N' then Y = put(X,best. -L) ;
run;
しかし、これをXが文字型の場合のデータセットAに対して実行すると
「ERROR : 出力形式 $BEST が見つからないか、またはロードできません。」
となります。else ifステートメントが実行されることはないのですが、
コンパイルの時点で、文字型の変数に数値用のフォーマット充てようとしてるぞバカって
早とちりされてエラーになっちゃいます。
ので、
proc sql noprint;
select TYPE into: MTYPE
from DICTIONARY.COLUMNS
where LIBNAME="WORK" and MEMNAME="A";
quit;
%macro m;
data B;
set A;
%if &MTYPE = char %then Y = X ;
%else %if &MTYPE = num %then Y = put(X,best. -L) ;;
run;
%mend m;
%m
のように、一旦Xの型をマクロ変数に格納して(例ではSQL使いましたが方法は何でもいいです)、それによって%ifで
マクロ内で実行されるコードを分岐させるといった方法をとれます。
ですが!!はっきりいって面倒くさい!
型によって実行されるコードが複雑な処理で、厳密に分けたい場合は、上記の感じでいいのですが単純にbestあてて文字にしたいだけなら、以下のような外法もあります
options missing ='';
data B ;
set A;
Y = cats(X,'');
run;
options missing ='.';
cat系関数は、基本文字変数に対する関数ですが、実は数値型の変数を指定すると
自動でbestフォーマットをあてて処理してくれます。暗黙の型変換ではなく関数の
働きによるものなので、結果は同じでもこの場合NOTEがでないんですね。
文字変数だった場合は、ブランクをくっつけているだけなので何もおきません。
なんか、ログを綺麗にするためだけの詐欺みたいな感じですけど。
options missing ='';は、Xが数値変数且つnullだった場合に「.」が文字化されないようにするための一手ですね。
何かほかにいいやり方をお持ちの方は是非教えてください。
まあ、そもそも型がぶれるっていう状況がよくないんですが。
0 件のコメント:
コメントを投稿