2016年7月6日水曜日

マクロ言語入門8:マクロ内での条件分岐処理【%IF】




マクロ内で「%IFステートメント」を使って、処理を条件によって分岐させる方法を紹介します




構文

%IF  条件式  %THEN  %DO;

          条件式がTRUEになった場合の処理

%END;
%ELSE %DO;

          条件式がFALSEになった場合の処理

%END;

  • %IFの条件式の判定法に注意! 例えば、
    • 「%IF 120>13」の条件は想定通り「TRUE」になりますが、
    • 「%IF 120.0>13.0」の条件は想定に反し「FALSE」になります
    • 理由は以下リンク記事で説明
    • https://sas-boubi.blogspot.com/2018/10/if.html
    • (SAS社の%IFのページにはこの事について触れていないので気づきにくい。。)




例1

%macro TEST( FLG );

   %if &FLG = Y %then %do;
       proc print data=SASHELP.CLASS;
       run;
   %end;

%mend;

%TEST();
%TEST(Y);


マクロ変数FLG に 「Y」 と入っていたらPRINTプロシジャが実行されます。
気をつけたいのがデータステップと勝手が違い、「%if &FLG = "Y"」というようにダブルクォーテーションで囲う必要はありません。

%IFステートメントではクォーテーションもテキストとして解釈されます。つまり「Y」という文字ではなく「"Y"」という文字として解釈されてしまいます。




例2

%macro TEST( FLG );

   data DT1;
       VAL1 = 1;
       %if &FLG = Y %then %do;
           VAL2=1;
       %end;
   run;

%mend;

%TEST();

 VAL1 
    1  


マクロ変数FLG に 「Y」 と入っていたら変数VAL2を作って「1」を代入するマクロです。
これ実はかなり便利です。なんでかというと、以下のように通常のIF文で同じようなことをやろうとすると、、


%let YN=;

data DT1;
    VAL1 = 1;
    if "&YN"="Y" then do;
        VAL2=1;
    end;
run;

 VAL1 
 VAL2  
    1      .


作りたくないVAL2が出来てしまいます。
これはたとえ実行されない文でもデータステップ内に書かれている変数はまず自動で変数の枠だけ作られてしまうという性質があるからです。

一方、%IFは通常のプログラムとは別のところで動くので、この動きを回避できちゃいます。




取り扱い注意


①「マクロ変数Xが欠損値だったら~」という%IFを書きたい場合

%if &X = %then %do;


少し違和感ありますがこれでOK(未確認ですが、昔のバージョンだとこの書き方ではERRORが出たらしい?)



② %IFが誤作動する例

%if &x = eq %then %do;


マクロ変数Xの値が「eq」かどうかを条件にしていますが、「eq」は「=」を意味しているので、演算子として解釈されて誤作動を起こして正しい結果が得られません。


他に誤作動を起こす文字は多数ありますが、それらは以下リンク記事で解説しているような「クォート処理」をする必要があります。


以下、適当にクォート処理を入れてみた例ですが、マクロ変数に格納される値によってはまだ誤作動を起こす危険があります。

%if %bquote(&x) = %str(eq) %then %do;

状況にあわせてどのクォート関数を使うのか、どのタイミングでクォート処理をするのかを判断する必要があります!




IF と %IF の大きな違い


  •  IFはデータステップ内で実行するステートメント
  •  %IFはデータステップ内とか外とかそういう概念がありません。


つまり%IFでは以下のようにデータセットの中にある変数の値を評価することは出来ません。

X 勘違い注意 X
%macro TEST;

data DT1;
    A=1;
    %if A=1 %then %do;
        B=1;
    %end;
run;

%mend;
%TEST;

%IFでは上記のプログラムを「A」という文字列と「1」という文字列がイコールかどうかを評価しちゃいます。
当然イコールじゃないので中の 「B=1;」 は実行されません。




0 件のコメント:

コメントを投稿