2021年11月15日月曜日

「PROC SQL」と「ODS OUTPUT の PERSIST=RUN」のコンボ技



まず今回のコンボ技を理解するには「ODS OUTPUTのPERSIST=RUN」の知識が必要なので、先に以下リンク記事をご覧ください。

ODS OUTPUTで出力結果を結合する②PERSIST=RUN

 

それでは本題。以下のプログラムをご覧ください。

ods select none;
ods output SQL_Results(persist=run)=out1;

proc sql;
 select count(*) as c1 from sashelp.class;
 select count(*) as c1 from sashelp.cars;
 select count(*) as c1 from sashelp.baseball;
quit;

ods output close;
ods select all;


一応、細かく説明しておくと、

  • PROC SQLは対話型プロシジャなので、1つのプロシジャで複数の集計をいっぺんに行ってます。
  • 「ODS OUTPUTのPERSIST=RUN」で対話型プロシジャ内のそれぞれの集計結果について、出力オブジェクトの名前が共通するものを縦結合しています。(今回の場合はすべての集計で、出力オブジェクトの名前が「SQL_Results」という名前で共通している)
  • 「_RUN_」という変数が勝手に作られました。RUNグループのIDと推測されます。SQLの場合は「RUNステートメント」は記述不要なので、実行グループ(セミコロン「;」で終わる文)のIDですね。
  • ちなみにPROC SQLで「NOPRINTオプション」を設定するとODS OUTPUTが使えない(データセットに出力されない)ので注意



ID振って縦結合してくれるのが便利。他の方法でも同じこと出来るけど、こっちのほうが文が短く済む場合があります。


ただし私自身、単純な集計でしか使ったことないので、各自利用する際は結果が希望通りのものになるか、ご確認下さい。

また、ODS OUTPUTで出力すると変数属性(変数名、length、formatなど)が自動調整される場合があるのでご留意ください。(以下リンク記事参照)

「ODS OUTPUT」で変数属性が自動調整される件



2021年11月1日月曜日

ODS OUTPUTで出力結果を結合する②PERSIST=RUN



前回の続きで、今回はODS OUTPUTの「PERSIST=RUN」というオプションを紹介します。


まずは以下の例をご覧ください。

データセット「SASHELP.CLASS」と「SASHELP.BMT」の定義情報をデータセットOUT1に出力しています。特に問題なく出力できています。

ods output Variables = out1;

   proc datasets lib=sashelp;
      contents data=class;
      contents data=bmt;
   run;
   quit;

ods output close;

データセット OUT1



ここから本題。DATASETSプロシジャは対話型プロシジャです(対話型プロシジャについては以下参照)

https://sas-boubi.blogspot.com/2018/01/runquit.html


そして今度は、説明のため、以下の通りあえて対話型プロシジャを意識した書き方に変えて実行してみます。

😟失敗例

ods output Variables = out1;

   proc datasets lib=sashelp;

      /* RUNグループ1: データセットに出力される */
      contents data=class;
      run;

      /* RUNグループ2: データセットに出力されない */
      contents data=bmt;
      run;

   quit;

ods output close;

データセットOUT1

対話型プロシジャの結果のうち、最初のRUNグループの結果しかデータセットに出力されませんでした。




😄解決策1(グループ毎にODS OUTPUTを記述

proc datasets lib=sashelp;

   /* RUNグループ1 */
   ods output Variables = out1;
   contents data=class;
   run;

   /* RUNグループ2 */
   ods output Variables = out2;
   contents data=bmt;
   run;

quit;
ods output close;

データセットOUT1

データセットOUT2

上の例では「RUNグループ」毎にODS OUTPUTを記述して、「RUNグループ」毎にデータセットを出力しています。プロシジャの中にODS OUTPUTを記述しているので、ちょっと違和感を感じるかもしれませんが、ちゃんと動きます。



もうひとつ解決策。これが紹介したかったんですが「PERSIST=RUN」というオプション。

以下のように、対話型プロシジャ内で、出力オブジェクトの名前が一緒であれば(今回の場合は「Variables」)、結合してデータセットに出力することが出来ます。


😄解決策2(PERSIST=RUN

ods output Variables(persist=run) = out1;

   proc datasets lib=sashelp;

      /* RUNグループ1 */
      contents data=class;
      run;

      /* RUNグループ2 */
      contents data=bmt;
      run;

   quit;

ods output close;

データセットOUT1

注意点:
ODS OUTPUT内に対話型プロシジャを複数書いても、出力できるのは最初のプロシジャのみ。




ちなみに、SQLプロシジャも対話型プロシジャですが「RUNグループ」ではなく、以下のように実行グループ(セミコロン「;」で終わる文)毎に実行されます。そこが違うだけでSQLプロシジャについても今回紹介した2つの解決策を適用できます。

ods output SQL_Results(persist=run) = out1;

   proc sql;

      /* 実行グループ1 */
      select count(*) as c1 from sashelp.class;

      /* 実行グループ2 */
      select count(*) as c1 from sashelp.bmt;

   quit;

ods output close;

データセットOUT1

PERSIST=オプションはSQLプロシジャと相性が良いので、今度その辺りも紹介したいと思います。