2018年9月26日水曜日

2つの文字を大文字・小文字区別せずに比較する





クマのプーさんの実写映画のやつ観に行ってきました。
プーさんが異常に可愛かったです。あとプーさんってぬいぐるみ設定だったんですね、知らなかった。。




プーさんの話は置いといて、
タイトルの通り、2つの文字を大文字・小文字区別せずに比較する方法を紹介したいと思います。


サンプルデータ

data test;
input a:$10. b:$10.;
cards;
pooh POOH
honey hunny
;



大文字・小文字区別せずに比較する

data out1;
  set test;

  /* 比較する文字がシングルバイト文字のみの場合 */
  if compare(a,b,'i') = 0 then same_flg1=1;

  /* 比較する文字に日本語等マルチバイト文字を含む場合 */
  if kcompare(a,b,'i') = 0 then same_flg2=1;

run;





COMPARE( 対象変数1, 対象変数2, 'i' )」というように、3つめの引数に「'i'」と指定することで大文字・小文字区別せずに比較することができます。
戻り値が「0」なら一致してるということです。

「COMPARE関数」は日本語等のマルチバイト文字に対応していないので、マルチバイトを含む場合は「KCOMPARE関数」を使用します。



2018年9月18日火曜日

【OPTIONS APPEND / INSERT】システムオプションに設定値を追加する。





例として、FMTSEARCHシステムオプションに設定値を追加してみます。
  • FMTSERACHシステムオプションは「CASサーバーでのフォーマットライブラリの検索順には適用されない」とのことなので注意(CASは使用したことないので詳細不明。詳しくはリファレンスを参照下さい)


それと、今回紹介する方法「OPTIONS APPEND / INSERT」は環境等によって挙動が異なります。
詳細は記事の最後らへんに注意点として記載。




ではまず、FMTSEARCHシステムオプションの設定値をログに出力してみます。

%put %sysfunc(getoption(fmtsearch));

ログ
(WORK LIBRARY)


WORK、LIBRARYの順に設定されていますね。




「APPENDシステムオプション」を使う

options append=(fmtsearch=myfmt);
%put %sysfunc(getoption(fmtsearch));

ログ
(WORK LIBRARY MYFMT)



MYFMTというライブラリが末尾に追加されました。
APPENDシステムオプションは、システムオプションの末尾に設定値を追加することが出来ます。


構文

 OPTIONS APPEND=( システムオプション名 = 末尾に追加する設定値 );





「INSERTシステムオプション」を使う

options insert=(fmtsearch=myfmt2);
%put %sysfunc(getoption(fmtsearch));

ログ
(MYFMT2 WORK LIBRARY MYFMT)



MYFMT2というライブラリが先頭に追加されました。
INSERTシステムオプションは、システムオプションの先頭に設定値を追加することが出来ます。


構文

 OPTIONS INSERT=( システムオプション名 = 先頭に追加する設定値 );






注意点


今回の方法で設定できるシステムオプションは環境・実行方法によって異なります。
以下を実行すると、設定できるシステムオプションがログに出力されます。

proc options listinsertappend;
run;

ただし、一部のシステムオプションはSAS起動時(構成ファイルまたはSASコマンドにて指定)のみ設定可能です。




その他メモ


以下のように何回も実行すると、同じ設定値が追加され続けちゃう事があるので、気を付けてくださいね。

options append=(fmtsearch=abc);
options append=(fmtsearch=abc);
%put %sysfunc(getoption(fmtsearch));

ログ
(WORK LIBRARY ABC ABC)





2018年9月10日月曜日

PROC SQL / FedSQL / DS2 の「STIMERオプション」でログに各ステップ毎のパフォーマンスを表示する





以下はPROC SQLで何個かステートメントを書いて実行した結果

proc sql;
  create table dt1 as select * from sashelp.class;
  create table dt2 as select * from sashelp.cars;
quit;



ログ
 72         proc sql ;
 73           create table dt1 as select * from sashelp.class;
 NOTE: テーブルWORK.DT1(行数19、列数5)が作成されました。

 74           create table dt2 as select * from sashelp.cars;
 NOTE: テーブルWORK.DT2(行数428、列数15)が作成されました。

 75         quit;
 NOTE: PROCEDURE SQL処理(合計処理時間):
       処理時間           0.00 秒
       CPU時間            0.01 秒



続いてSTIMERオプションをつけた場合

proc sql stimer;
  create table dt1 as select * from sashelp.class;
  create table dt2 as select * from sashelp.cars;
quit;


ログ
 74         proc sql stimer;
 NOTE: SQL Statement処理(合計処理時間):
       処理時間           0.00 秒
       CPU時間            0.00 秒
     
 75           create table dt1 as select * from sashelp.class;
 NOTE: テーブルWORK.DT1(行数19、列数5)が作成されました。

 NOTE: SQL Statement処理(合計処理時間):
       処理時間           0.00 秒
       CPU時間            0.00 秒
     
 76           create table dt2 as select * from sashelp.cars;
 NOTE: テーブルWORK.DT2(行数428、列数15)が作成されました。

 NOTE: SQL Statement処理(合計処理時間):
       処理時間           0.00 秒
       CPU時間            0.00 秒
     
 77         quit;
 NOTE: PROCEDURE SQL処理(合計処理時間):
       処理時間           0.00 秒
       CPU時間            0.00 秒


ログにステートメント毎のパフォーマンスが表示されるようになります。
「PROC DS2」や「PROC FedSQL」でも同様にSTIMERオプションを設定できます。
私自身はDS2使う時によくこのオプション指定することはあります。


※「STIMERオプション」を利用するには、システムオプションで「OPTIONS STIMER」か「OPTIONS FULLSTIMER」も設定されている必要があります。


2018年9月4日火曜日

PROC DS2でタイムゾーン関係の処理をする「TZパッケージ」



DS2プロシジャの「TZパッケージ」でタイムゾーン関係の処理ができます
アメリカとかだとタイムゾーンが地域によって違うから、パッケージ化するほどの需要あるんですかね。



以下は簡単な例です。

 proc ds2;
 data _null_;
    method init();
       dcl package tz t();
       dcl double utc tokyo having format nldatm20.;
       dcl double tokyo_offset having format time8.;

       /* UTC timeを取得 */
       utc = t.getutctime();
 
       /* Local timeを取得 */
       tokyo = t.getlocaltime('Asia/Tokyo');

       /* Offsetを取得 */
       tokyo_offset = t.getoffset('Asia/Tokyo');

       put utc=;
       put tokyo=;
       put tokyo_offset=;

    end;
 enddata;
 run;
 quit;

ログ
 utc=2018/09/04 11:56:47
 tokyo=2018/09/04 20:56:47
 tokyo_offset= 9:00:00


メソッドの中で「’Asia/Tokyo’」というように地域を指定していますが、タイムゾーンIDといって、「SAS timezone id」とかググれば地域ごとのタイムゾーンIDが載ってるSASのリファレンスが出てくるはずです。

該当する地域のタイムゾーンIDがない場合は、同じタイムゾーンを持つほかの地域を探して設定しましょう(夏時間を導入している地域では、そこも同じかどうか確認するのを忘れずに)

あとは構文自体も大したことないんで、詳細はリファレンスを見てみてください。




とりあえず私は業務で使う事ないんで、暇つぶし用のプログラムを書いて遊んでます。

 proc ds2;
 data _null_;
    method init();
       dcl package tz t();
       dcl double tokyo newyork honolulu vancouver having format nldatm20.;

       tokyo         = t.getlocaltime('Asia/Tokyo');
       newyork    = t.getlocaltime('America/New_York');
       honolulu    = t.getlocaltime('Pacific/Honolulu');
       vancouver = t.getlocaltime('America/Vancouver');

       put tokyo=;
       put newyork=;
       put honolulu=;
       put vancouver=;

    end;

 enddata;
 run;
 quit;

ログ
 tokyo=2018/09/04 20:51:00 
 newyork=2018/09/04 07:51:00
 honolulu=2018/09/04 01:51:00
 vancouver=2018/09/04 04:51:00


適当な地域の現在時刻を調べて「あーニューヨーカーは今頃寝てるのか、いやむしろ寝てないのかな」とか妄想するために使うものだと思っています。
一応、夏時間も考慮されているっぽい(夏時間が存在する地域でちゃんと夏時間の日時になってたんで)




2018年9月2日日曜日

【小ネタ】抽出条件のないWHEREステートメント





以下のように抽出条件のない空のWHEREステートメントを書いてもエラーになりません。

data a;
   set sashelp.class;
   where;
run;

抽出条件が掛かれていないので、すべてのオブザベーションが読み込まれます。




これが出来るからなんなのか、、っていうと、例えば以下のようなマクロを定義したい場合ですね。

* マクロ定義 ;
 %macro test( wh= );

   data a;
      set sashelp.class;
      where &wh;
   run;

 %mend;


* マクロ実行 ;
 %test( wh=age=13 )  /* マクロ実行:抽出条件を指定する場合 */
 %test( wh= )              /* マクロ実行:抽出条件を指定しない場合 */



抽出条件があればマクロ変数whに条件を指定すればいいし、なければ何も指定しなければいいだけ。
抽出条件がある場合とない場合で%ifとか使って分岐処理とかさせる必要ありません。







ただ、where=データセットオプションでは条件を空にするのはダメのようです。

data a;
   set sashelp.class (where=());
run;

ログ
 ERROR: WHERE式の読み込み中に、構文エラーが発生しました。

 ERROR 22-322: 構文エラーです。次のいずれかを指定してください: 名前, 引用符で囲んだ文字列, 
               数値定数, 日時定数, 欠損値, INPUT, PUT.  

 ERROR 76-322: 構文エラーです。ステートメントを無視しました。

 ERROR 6-185: データセットのオプションリストに')'のかっこがありません。

 ERROR 79-322: )を指定してください。

 NOTE: エラーが発生したため、このステップの処理を中止しました。
 WARNING: データセットWORK.Aは未完成です。このステップは、0オブザベーション、
          0変数で停止しました。
 WARNING: このステップを中止したため、データセットWORK.Aを置き換えていません。


ログが怒りすぎ、なんかかわいいです。



なので私は以下のように書いてSASをごまかしています。

data a;
   set sashelp.class (where=(1));
run;

「1」は真(true)の意味です。
常に条件が真(true)の状態、つまり全オブザベーションが読み込まれます。


「0」ってのもあります。

   set sashelp.class (where=(0));


この「0」は偽(false)の意味です。
常に偽(false)の状態、つまり全オブザベーション読み込まれません。



勿論この書き方はwhereステートメントでも通用します。

data a;
   set sashelp.class;
   where 1;
run;