2014年8月22日金曜日

Call Symputルーチンによるマクロ変数作成の豆知識

マクロ変数は、プログラム内で場所を選ばず展開できる「グローバルマクロ変数」と
%MACRO ~ %MEND;内でのみ展開できる「ローカルマクロ変数」があります。


また、マクロ変数は下記の方法で定義することができます。
 1.%LETステートメント
   ・%MACRO ~ %MEND;内で宣言 ・・・ 「ローカルマクロ変数」として定義
   ・%MACRO ~ %MEND;外で宣言 ・・・ 「グローバルマクロ変数」として定義

 2.%MACROステートメント内のパラメータ
   ・「ローカルマクロ変数」として定義

 3.%DOループのインデックスマクロ変数
   ・「ローカルマクロ変数」として定義
    
 4.Call Symputルーチン
   ・通常は%MACRO ~ %MEND;の内外問わず「グローバルマクロ変数」として定義


 ただし、4.Call Symputルーチンは下記の様な場合、「ローカルマクロ変数」として定義されます。
     A.%MACRO ~ %MEND;内でCall Symput以前にローカルマクロ変数が定義されている場合
     B.PROC SQLの後で、Call Symputを使用した場合
     C.マクロ呼び出しの際にマクロ変数SYSPBUFFを作成した場合
     D.同じ%MACRO ~ %MEND;内に、「&~」や「%~」を含む%GOTOステートメントがある場合
   


さて、今回はA.のパターンについて紹介したいと思います。




以前、現場で「基準年月」から「6ヶ月間」分のデータを取得し集計するご依頼をいただき

私は、6ヶ月分のデータを取得する下記の様なマクロを作成しました。

※実際に作成したプログラムとは、多少変えてあります。


  %let yymm = 1403;  /* 基準年月 */

  %macro aaa;           /* 基準年月から6ヶ月分の年月を取得するマクロ */

    %do i = 1 %to 6;

         data _null_;
            ym = put(intnx('mon',input("&yymm",yymmn4.),&i-1),yymmn4.);
            call symput("yymm&i",compress(ym));
         run;

    %end;

  %mend;
  %aaa;
  
  %put 1ヶ月目 = &yymm1;  /* チェック用 */



ところが、プログラムを作成し実際に実行してみると%putステートメントの処理の際に、

次の様なメッセージがログに出ました。

 Warning : 記号参照 YYMM1 を展開していません。



思わぬWarningの出現に首をかしげてしまいました。



Warningの原因は、%doステートメント内のマクロインデックス変数 &i でした。

&i がCall Symput以前に定義されていたため、マクロ変数 &yymm1 は「ローカルマクロ変数」として

定義されてしまったのです。



色々、検証してみた末、原因が判明したので、私は下記の様な対処方法を考えました。

 A.) Call Symputで定義したマクロ変数を%GLOBALステートメントを使用してグローバル化する


         %let yymm = 1403;  /* 基準年月 */

         %macro aaa;           /* 基準年月から6ヶ月分の年月を取得するマクロ */

           %do i = 1 %to 6;

                 %global yymm&i;  

                 data _null_;
                    ym = put(intnx('mon',input("&yymm",yymmn4.),&i-1),yymmn4.);
                    call symput("yymm&i",compress(ym));
                 run;

           %end;

        %mend;
        %aaa;
  
        %put 1ヶ月目 = &yymm1;  /* チェック用 */



  B.) マクロを使用しない


          %let yymm = 1403;  /* 基準年月 */
    
          data _null_;
             do i = 1 to 6;
                 ym = put(intnx('mon',input("&yymm",yymmn4.),i-1),yymmn4.);
                 call symput(compress('yymm' || put(i,best.)),compress(ym));
             end;
          run;

          %put 1ヶ月目 = &yymm1;  /* チェック用 */



A・Bどちらのパターンでも「グローバルマクロ変数」として定義され

私の望んだ結果を得ることができました。



皆さんも頭の片隅にでも留めておいて頂けたら意外と役に立つかもしれません。


以上、文章での説明が苦手なので読みにくい点が多々あると思いますが、
最後まで読んで下さった方はありがとうございました。

0 件のコメント:

コメントを投稿

ツイート数からみる"バーチャルYouTuber"ブーム

今や YouTuber の話題の半分を占めるほどのクチコミ数に 当社が提供するソーシャルビッグデータ検索ツールの「 beInsight (ビーインサイト)」を使って、話題の「バーチャル YouTuber 」について調べてみました。 「バーチャル YouTuber...