2018年11月28日水曜日

コンパイルしたマクロを削除する





マクロを削除する方法1

%SYSMACDELETE  マクロ名 ;

  • 「WORK.SASMACR」内にあるマクロを削除することが出来ます
  • サイドセッションを使用するアプリケーションやプログラムでは、マクロが「WORK.SASMACn」(nは一意の整数)に格納されるため、該当セッションの「WORK.SASMACn」内のマクロが削除対象になる


%sysmacdelete test1;






マクロを削除する方法2

PROC CATALOG  CAT=ライブラリ名.カタログ名  ET=MACRO;
     DELETE  マクロ名1  マクロ名2 ・・・ ;
RUN;
QUIT;

  • 対象のライブラリとカタログ名を指定することが出来ます。
  • 削除したいマクロ名を列挙します。


proc catalog cat=mymac.sasmacr et=macro;
   delete test1 test2 test3;
run;
quit;






マクロを削除する方法3  (注意事項あり)

PROC CATALOG  CAT=ライブラリ名.カタログ名  KILL FORCE;
RUN;
QUIT;

  • カタログ内の「全エントリー」を削除します。
  • 「全エントリー」とはマクロだけでなくフォーマットなどのあらゆるエントリーを含みます。
  • 「KILL」オプションは PROC CATALOG 内の他のオプションやステートメントより先に動作します。たとえばDELETEステートメントで削除するマクロを指定していても意味はなく、カタログ内の全エントリーを削除してしまいます。


2018年11月22日木曜日

FIRSTOBS=, OBS=, WHERE を組み合わせたときの挙動




データセットオプション「FIRSTOBS=」と「OBS=」の紹介と、WHEREステートメントを組み合わせて使用した時の挙動について、まとめておきます。



データの状態によっては結果がバグる事があって、その辺の注意点については最後に別記事のリンク貼ってるので参照下さい。



Sample data
data a;
   do i=1 to 10;
     output;
   end;
run;





FIRSTOBS=オプション

・処理(読込み)を開始するオブザベーションを指定できます。

proc print data=a (firstobs=3);
run;




OBS=オプション

・何オブザベーション目まで処理するか(読み込むか)を指定できます。

proc print data=a (obs=3);
run;




FIRSTOBS=, OBS=, WHERE の組み合わせ

ここから本題。以下のプログラムで結果が予測できればバッチリです。

proc print data=a (firstobs=2 obs=3);
  where i>5;
run;


解説
・まずWHEREでオブザベーションを抽出。
・抽出したオブザベーションに対して、FIRSTOBS=とOBS=を適用。
・FISTOBS=とOBS=で共通する範囲にあるオブザベーションが処理対象となる。


以下にイメージを載せておきます。


ちなみに

SETステートメントとかでもこれらのオプションが使えます。

data b;
  set a (obs=3);
run;



注意


以下の記事で、FISTOBS=オプション自体の落とし穴も紹介しています。
FIRSTOBSオプションの落とし穴




2018年11月20日火曜日

FORMATの落とし穴【デフォルト長】




PROC FORMAT の VALUEステートメントでありがちな落とし穴。
以下のプログラムと結果をご覧ください。結果は想定通りでしょうか?

proc format;
   value $FMT
       "a"    = "x"
       "abc" = "y"
   ;
run;

data DT1;
   format VAR1 $FMT.;
   VAR1 = "abc";
run;

  VAR1  
  x 

変数VAR1は "abc" なのでフォーマット$FMTを貼りつけると "y" と表示されるはずが、 "x" が表示されてしまいました。



原因

これは「デフォルト長 (Default Length)」というものが関係してます。
例えば、今回の例で

proc format;
   value $FMT
       "a"    = "x"
       "abc" = "y"
   ;
run;


等号の右側に定義した値 ("x" と "y") の文字の長さは1バイトです。
この長さが、そのフォーマットの「デフォルト長」というものになります。
(定義した値が複数ある場合は、右側の文字の長さが最も大きいものがそのフォーマットの「デフォルト長」になる)



そしてこのフォーマット$FMTは、以降のFORMATステートメントでデフォルト長となった1バイトしか視界に入らなくなります。
どういう事かというと、、

data DT1;
   format VAR1 $FMT.;
   VAR1 = "abc";
run;

変数VAR1 の値 "abc" から先頭の1バイトの値 "a" だけを見て対応するフォーマット値を表示しようとします。



ちょうど PROC FORMAT で "a" = "x" と定義してたので、この値が表示されちゃったというわけですね。

proc format;
   value $FMT
       "a"    = "x"
       "abc" = "y"
   ;
run;


ちなみに...

以下のように、PROC FORMATから1つ目の「"a" = "x"」をコメントアウトして定義から外すと、、、

proc format;
   value $FMT
/*       "a"    = "x" */
       "abc" = "y"
   ;
run;

data DT1;
   format VAR1 $FMT.;
   VAR1 = "abc";
run;

  VAR1  
  a 

まずは変数VAR1 の値 "abc" から先頭の1バイトの値 "a" だけを見て対応するフォーマット値を表示しようとしますが、
対応するフォーマットがないので、そのままの値 "a" が表示されちゃってるわけですね。
この辺の挙動を知らないと「なんじゃこりゃ??」となってしまいますね。



解決策

変数VAR1 の値 "abc" の文字の長さは3バイトなので、3バイト全部読み込んで表示する必要があります。
解決策としては以下の2つの方法があります。


解決策①
proc format;
   value $FMT (default=10)
       "a"    = "x"
       "abc" = "y"
   ;
run;

data DT1;
   format VAR1 $FMT.;
   VAR1 = "abc";
run;

  VAR1  
  y 

「DEFAULT=オプション」によってこのフォーマットのデフォルト長を 10 に広げています。


解決策②
proc format;
   value $FMT (max=10)
       "a"    = "x"
       "abc" = "y"
   ;
run;

data DT1;
   format VAR1 $FMT10.;
   VAR1 = "abc";
run;

  VAR1  
  y 

「format VAR1 $FMT10.」として、FORMATステートメントで、フォーマット名の後ろに幅を指定することも出来ます。
今回は幅を10に設定して問題なく動作していますが、「出力形式〇〇に指定した幅は無効です」みたいなERRORが出る事があります。そういった場合はFORMATプロシジャで「value $FMT (max=10)」というように、指定可能な幅の最大値を設定する必要があります。




See also

インフォーマットでも同様の落とし穴があります。
INFORMATの落とし穴【デフォルト長】


ポイント
・文字値から数値に変換するINVALUEステートメントでは「左側」に定義した文字の長さがデフォルト長になる
・VALUEステートメントでは「右側」に定義した文字の長さがデフォルト長になる


2018年11月1日木曜日

SQLビューは同じ変数名が複数あってもエラーにならない




SQLビューの落とし穴です。以下をご覧ください。

proc sql;
   create view myview as
   select  name,
              111 as var1,
              222 as var1
   from  sashelp.class;
quit;


proc print data=myview noobs;
run;


なにこれ、VAR1が2つ存在しちゃってる、エラーにもなってない。。
実はCREATE VIEWでは、同じ名前の変数がいくつも存在する状態を作り出すことが出来てしまうんです。



では、先ほどのSQLビューに対して、VAR1を選択してPROC PRINTすると、、

proc print data=myview noobs;
   var var1;
run;


1個目のVAR1がプリントされました。2個目はどうした。



私自身、この挙動を知らずにミスったことがあります。
その時の状況として、変数が数十個あるデータセットに対して、

select  *, x+y as var1

みたいなselect文を書いたSQLビューを作りました。ですが元々データセットにVAR1っていう変数が存在していて、それを知らずにSQLビューの中でもVAR1っていう変数を作ってしまっていました。

このSQLビュー内で作ったVAR1に対して、

proc means data=○○;
   var var1;
run;

みたいな事をやろうとしたところ、元々データセットに存在しているVAR1に対して集計が行なわれてしまい、結果がおかしい!?ってなりました。



See also...
SQLビューの作成と落とし穴①