2017年9月19日火曜日

【LENGTH/LENGTHN関数】文字列が何バイトか返す




「LENGTH関数」と「LENGTHN関数」は、文字列が何バイトなのかを返す関数です。

最近まで「LENGTHN関数」の存在忘れてましたが、場合によって使い分ける必要がありそうです。



構文



    LENGTH(  変数または文字列  )
    LENGTHN(  変数または文字列  )


① 指定した変数に含まれる値または文字列が何バイトかを返す。
② 変数または文字列が Null の場合、返される値は以下の通り。

・LENGTH関数 = 1
・LENGTHN関数 = 0






*** Sample data ;
data DT1;
    X="abc"; output;
    X=""; output;
run;







*** lenth, lengthn関数を使う ;
data DT2;
    set DT1;
    LEN   = length(X);
    LENN = lengthn(X);
run;

「LENGTH関数」の場合、文字列が Null の時に1が返されてしまうので、そこを想定し忘れるとバグを起こすことがありますよね。

そんな時は「LENGTHN関数」つかいましょう。


2017年9月13日水曜日

PROC FREQ と ODS OUTPUT の落とし穴



PROC FREQ の結果を ODS OUTPUT でデータセットに出力する際の落とし穴です。



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

うまくいく例
ods output OneWayFreqs=OUT1;

   proc freq data=SASHELP.CLASS;
      table SEX AGE;
   run;

ods output close;



次にうまくいかない例。

うまくいかない例
ods output OneWayFreqs=OUT1 (where=(AGE=13));

   proc freq data=SASHELP.CLASS;
      table SEX AGE;
   run;

ods output close;

ログ
ERROR: 変数AGEはファイルWORK.OUT1にありません。


WHERE=オプションを追加したらERRORが出ちゃいました。
構文的には問題ないのに何故でしょう?



原因


以下のように ODS TRACE で出力オブジェクト名をログに表示してみると、、

ods trace on;

proc freq data=SASHELP.CLASS;
   table SEX AGE;
run;

ods trace off;

ログ
出力の追加 :
-------------
名前 :         OneWayFreqs
ラベル :       一元表
テンプレート : Base.Freq.OneWayFreqs
パス :         Freq.Table1.OneWayFreqs
-------------

出力の追加 :
-------------
名前 :         OneWayFreqs
ラベル :       一元表
テンプレート : Base.Freq.OneWayFreqs
パス :         Freq.Table2.OneWayFreqs

出力オブジェクト「OneWayFreqs」が2つ出てますね。

PROC FREQ の TABLEステートメントで「table SEX AGE」と書いているため、
SEXとAGEそれぞれに出力オブジェクト「OneWayFreqs」が出来ている事を表しています。



そしてここから予想になるのであしからずという感じですが、

ods output OneWayFreqs=OUT1 (where=(AGE=13));

   proc freq data=SASHELP.CLASS;
      table SEX AGE;
   run;

ods output close;

と書いたときの挙動として、

① 変数 SEX の集計結果をデータセット OUT1 に出力
② 変数 AGE の集計結果をデータセット OUT1 に出力

となりますが、どうやらWHERE=オプションは上記①②のそれぞれで実行されている気がします(色々実験した結果の予想)

つまり①の時点では出力データセットに 変数 AGE の集計結果が存在していないので、「where=(AGE=13)」は ”存在していない変数に対するWHERE条件” となりERRORが出てしまったというわけですかね。


内部挙動は予想になってしまうので、
この辺ちゃんと説明しているサイトなどご存知の方いたら教えてほしいです。


2017年9月8日金曜日

【KCOUNT関数】変数値に2バイト文字が含まれているか確認する方法




データセットの中身を英語で作らなきゃいけないことがあります(製薬業界だとCDISC対応とかで)

そういう時に、キーボードが全角の設定になっていたせいで間違えて全角のアルファベットや数字が入り込んでしまうことがありますよね。


、、2バイト文字が入り込んでいないか確認したい、、、そんな時に使えるのが、KCOUNT関数です。


構文

  KCOUNT( 変数 )


・指定した変数の中に含まれる2バイト文字の数を返す。





* Sample data ;
data DT1;
input X:$20.;
cards;
ABCD
ABCD
あいうえお
123五
;
run;










* 2バイト文字があるか確認する ;
data DT2;
 set DT1;
 Y = kcount(X);
run;

2017年9月7日木曜日

関数内での配列の使い方



「定義した配列を関数の中で使うにはどのように書けばよいですか?」

という質問を頂くことがあるので、簡単に紹介します。



* Sample data ;
data DT1;
    X=1;
    Y=2;
    Z=3;
run;






* 関数内で配列を使う例 ;
data DT2;
    set DT1;
    array AR(*) X Y Z;

    * 例① ;
    TOTAL1 = sum( AR(1), AR(2) );

    * 例② ;
    TOTAL2 = sum( of AR(*) );
run;



「例①」では配列ARの1個目と2個目の要素を指定しています。
「例②」では配列ARの全要素を指定しています。

特に難しいことはないですね。

2017年9月5日火曜日

HTML出力で、カーソルを合わせた時にテキストをポップアップさせる




PROC REPORT や PROC PRINT などでHTML出力する際「 STYLE = ( FLYOVER="テキスト" ) 」という感じでポップアップテキストを仕込むことが出来ます。



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

proc report data=SASHELP.CLASS nowd;
    column NAME AGE HEIGHT;
    compute AGE;
       if AGE.sum > 12 then
          call define("AGE.sum","style","style(calldef)=[color=blue flyover='AGE > 12']");
    endcomp;
run;


STYLE=オプション内で、

・AGE>12 のレコードの年齢を青く表示するようにしています。

・同時に 「FLYOVER=オプション」を使ってAGE>12のレコードの年齢にカーソルを合わせると "AGE > 12" というテキストがポップアップされるようにしています。



そもそも「STYLE=オプション」って何?って方は以下記事も参照下さい。
REPORTプロシジャ入門8:書式の設定【STYLE=】

2017年9月2日土曜日

RTF出力時に文字のまわりをピカピカさせる



変なタイトルですよね。


文字を "{\animtext3 文字}" という感じで囲ってRTFで表示すると文字のまわりがピカピカします。

例1
data DT1;
   length TEXT $20.;
   TEXT="ネタ募集中";
run;

ods rtf file="出力したいパス\test.rtf";

   title "{\animtext3 SAS忘備録}";
   proc print data=DT1 noobs;
   run;

ods rtf close;

上の例では、タイトルのまわりにピカピカする演出が入って結構綺麗です。
{\animtext1 文字} ~ {\animtext6 文字} というように番号によって6種類のピカピカ演出が用意されているようです。



例2

陸上の順位毎にピカピカ演出を入れる例です。

*** データを用意 ;
data DT1;
infile cards dlm=",";
input NO:8. NAME:$50. TIME:8.;
cards;
1,{\animtext3 佐藤さん},10.40
2,{\animtext1 後藤さん},10.56
3,{\animtext4 伊藤さん},10.57
4,内藤さん,10.58
5,斉藤さん,10.59
run;











*** 出力 ;
ods rtf file="出力するパス\test2.rtf";

   title "{\animtext6 陸上100mタイム}";
   proc print data=DT1 noobs;
   run;

ods rtf close;


画像だとピカピカ加減が分かり辛いですね。
私みたいなヒマな人は試してみてその目で確認してみてください。

2017年8月30日水曜日

そのマクロ変数、ローカル?グローバル?⑥パズルみたいな事例



今回のシリーズ記事を書いたのは、以下記事のパズルみたいな事例をみて「なるほど、面白いなぁ」と思ったのがキッカケでした。



マクロ変数を作成するときに引っかかった話 (晴れ時々SAS)
http://dengonmemo.blogspot.jp/2017/07/blog-post.html

data DT_TEST ;
    _AA=1 ; output ;
    _AA=2 ; output ;
    _AA=3 ; output ;
run ;
%macro MCR_TEST ;

    *----------  ローカルマクロを指定;
    %let _aa2=123 ;
    data _NULL ;
        set DT_TEST ;
     
        *----------  グローバルマクロを指定;
        call symputx("_aa2",_N_,"g") ;
    run ;
    *----------  マクロ変数を呼び出し;
    %put &_aa2 ;

%mend ;

*----------  1回目:ローカルマクロとしての値(123)が返る;
%MCR_TEST ;


*----------  2回目以降:グローバルマクロとしての値(3)を返す;
%MCR_TEST ;


マクロ「MCR_TEST」を1回目に実行した時と、2回目に実行した時とで、「%put &_aa2;」の戻り値が異なってしまってるよ。というものです。


先日SASユーザー総会で「晴れ時々SAS」を運営されている方に記事のせてもOKの許可を頂いたので、「何故戻り値が実行する度に変わってしまったのか」を解説したいと思います。




マクロ実行「1回目」の挙動


%let _aa2=123 ;

まずは以下記事で紹介したフローチャートの通り、ローカルマクロ変数「_aa2」が作成されます。
(同名のマクロ変数が既に定義されていないかチェックし、定義されていない場合はローカルマクロ変数になる。)
http://sas-boubi.blogspot.jp/2017/07/let.html



data _NULL ;
    set DT_TEST ;

    *----------  グローバルマクロを指定;
    call symputx("_aa2",_N_,"g") ;
run ;

以下記事で紹介している CALL SYMPUTX でグローバルマクロ変数「_aa2」が作成されます。
http://sas-boubi.blogspot.jp/2017/08/blog-post_28.html

この時点で、
・ローカルマクロ変数 「_aa2」= 123
・グローバルマクロ変数「_aa2」= 3
が作成されたことになりますね。


%put &_aa2 ;

以下記事のフローチャートの通り、マクロ内でローカルとグローバルに同名のマクロ変数が存在する場合、ローカルマクロ変数の値を優先して展開するので、「%put &_aa2;」の戻り値は ”123” となります。
http://sas-boubi.blogspot.jp/2017/08/blog-post_17.html


マクロが終了すると、ローカルマクロ変数は消去されるので、グローバルマクロ変数「_aa2」= 3 だけが残ります。



マクロ実行「2回目」の挙動


%let _aa2=123 ;

マクロを1回目に実行したときにグローバルマクロ変数「_aa2」が残っていることに注目してください。
以下記事フローチャートの通り、グローバルに同名のマクロ変数が存在するので、グローバルマクロ変数を上書きします。
http://sas-boubi.blogspot.jp/2017/07/let.html


data _NULL ;
    set DT_TEST ;

    *----------  グローバルマクロを指定;
    call symputx("_aa2",_N_,"g") ;
run ;

CALL SYMPUTX でグローバルマクロ変数「_aa2」を上書きします。


この時点で、
・グローバルマクロ変数「_aa2」= 3
のみが存在することになりますね。


%put &_aa2 ;

グローバルマクロ変数しか存在しないので、戻り値は当然グローバルマクロ変数の値 ”3” が返されます。



パズルを解くみたいに入り組んじゃってますね。
実際にこのパズルに悩んで質問を頂くことがあります。