ちまたで話題のstreamプロシジャの紹介を私もしようと.まあ便利ですからねえアレ
beginから一番最後の;;;;までの内容を外部ファイルに出力することができるやつですね.
この記事ではstreamプロシジャのnoabsscmtオプションの紹介です.
このオプションはコメントを外部ファイルに出力するのに必要なものです.
%let _mac1 = "tst" ;
filename tst "st2.txt" ;
proc stream outfile=tst resetdelim="rd" noabsscmt ;
begin
hoge rd newline ;
/*ここはコメント*/ rd newline ;
hage rd newline ;
/*&_mac1*/
;;;;
とすると,以下のように出せます.
今回はst2というテキストファイルへの出力です.
ただしコメント部分のマクロ変数は展開されません.
hoge
/*ここはコメント*/
hage
/*&_mac1*/
2019年4月1日月曜日
2019年3月1日金曜日
luaでプログラムをループさせる話
luaでプログラムをループさせると言う試みです.
今までSASではマクロがその役割を担ってきましたが,luaでも出来ますよと言う紹介です.
以下に載せているのは,workにある3つのデータセット(tst tst1 tst2)の更新日時をログに表示するプログラムです.
マクロで書く場合とまったく同じ結果が得られますし,マクロで書くより実行ログが見やすいです.
繰り返しの対象となったプログラムのコードがログに表示されますし,luaのテーブルで与えた可変の情報が代入された状態でログにSASコードが生成されます.
その分ログが長くなりがちですが,どこで何が代入されてプログラムが実行されているのかがログを見て一発でわかるのでとても修正がしやすいです.
マクロを使うと結局ここではマクロ変数に何の値が入っているのかを確認するのが煩雑だと思います.mprintとか駆使すればいけますが ,アレもいまいち見やすい形でログに表示されないのではないでしょうか.
なにはともあれ,下のプログラムと実行ログを見てみてください.
以下実行プログラム
data tst ;
a = 1 ;
run ;
data tst1 ;
a = 1 ;
run ;
data tst2 ;
a = 1 ;
run ;
proc lua terminate;
submit ;
-- ログ整理用ダミー
sas.submit([[
data _null_ ;
run ;
]])
dataset = {}
dataset[1] = "work.tst"
dataset[2] = "work.tst1"
dataset[3] = "work.tst2"
for i, tag in ipairs(dataset) do
sas.submit([[
data _null_ ;
RCO = open("@tag@") ;
RC = attrn(RCO , "modte") ;
CL = close(RCO) ;
format RC e8601dt. ;
putlog "@tag@:" RC ;
run ;
]])
end
endsubmit;
run ;
/*実行ログ*/
2460 proc lua terminate;
2461 submit ;
2462
2463 -- ログ整理用ダミー
2464 sas.submit([[
2465 data _null_ ;
2466 run ;
2467 ]])
2468
2469 dataset = {}
2470 dataset[1] = "work.tst"
2471 dataset[2] = "work.tst1"
2472 dataset[3] = "work.tst2"
2473
2474 for i, tag in ipairs(dataset) do
2475 sas.submit([[
2476 data _null_ ;
2477 RCO = open("@tag@") ;
2478 RC = attrn(RCO , "modte") ;
2479 CL = close(RCO) ;
2480
2481 format RC e8601dt. ;
2482 putlog "@tag@:" RC ;
2483 run ;
2484 ]])
2485
2486 end
2487
2488 endsubmit;
2489 run ;
NOTE: Lua initialized.
data _null_ ;
run ;
NOTE: DATAステートメント処理(合計処理時間):
処理時間 0.00 秒
CPU時間 0.00 秒
data _null_ ;
RCO = open("work.tst") ;
RC = attrn(RCO , "modte") ;
CL = close(RCO) ;
format RC e8601dt. ;
putlog "work.tst:" RC ;
run ;
work.tst:2019-01-12T20:01:32
NOTE: DATAステートメント処理(合計処理時間):
処理時間 0.01 秒
CPU時間 0.01 秒
data _null_ ;
RCO = open("work.tst1") ;
RC = attrn(RCO , "modte") ;
CL = close(RCO) ;
format RC e8601dt. ;
putlog "work.tst1:" RC ;
run ;
work.tst1:2019-01-12T20:01:32
NOTE: DATAステートメント処理(合計処理時間):
処理時間 0.00 秒
CPU時間 0.00 秒
data _null_ ;
RCO = open("work.tst2") ;
RC = attrn(RCO , "modte") ;
CL = close(RCO) ;
format RC e8601dt. ;
putlog "work.tst2:" RC ;
run ;
work.tst2:2019-01-12T20:01:32
NOTE: DATAステートメント処理(合計処理時間):
処理時間 0.00 秒
CPU時間 0.00 秒
NOTE: TKLua terminated.
NOTE: PROCEDURE LUA処理(合計処理時間):
処理時間 0.35 秒
CPU時間 0.20 秒
今までSASではマクロがその役割を担ってきましたが,luaでも出来ますよと言う紹介です.
以下に載せているのは,workにある3つのデータセット(tst tst1 tst2)の更新日時をログに表示するプログラムです.
マクロで書く場合とまったく同じ結果が得られますし,マクロで書くより実行ログが見やすいです.
繰り返しの対象となったプログラムのコードがログに表示されますし,luaのテーブルで与えた可変の情報が代入された状態でログにSASコードが生成されます.
その分ログが長くなりがちですが,どこで何が代入されてプログラムが実行されているのかがログを見て一発でわかるのでとても修正がしやすいです.
マクロを使うと結局ここではマクロ変数に何の値が入っているのかを確認するのが煩雑だと思います.mprintとか駆使すればいけますが ,アレもいまいち見やすい形でログに表示されないのではないでしょうか.
なにはともあれ,下のプログラムと実行ログを見てみてください.
以下実行プログラム
data tst ;
a = 1 ;
run ;
data tst1 ;
a = 1 ;
run ;
data tst2 ;
a = 1 ;
run ;
proc lua terminate;
submit ;
-- ログ整理用ダミー
sas.submit([[
data _null_ ;
run ;
]])
dataset = {}
dataset[1] = "work.tst"
dataset[2] = "work.tst1"
dataset[3] = "work.tst2"
for i, tag in ipairs(dataset) do
sas.submit([[
data _null_ ;
RCO = open("@tag@") ;
RC = attrn(RCO , "modte") ;
CL = close(RCO) ;
format RC e8601dt. ;
putlog "@tag@:" RC ;
run ;
]])
end
endsubmit;
run ;
/*実行ログ*/
2460 proc lua terminate;
2461 submit ;
2462
2463 -- ログ整理用ダミー
2464 sas.submit([[
2465 data _null_ ;
2466 run ;
2467 ]])
2468
2469 dataset = {}
2470 dataset[1] = "work.tst"
2471 dataset[2] = "work.tst1"
2472 dataset[3] = "work.tst2"
2473
2474 for i, tag in ipairs(dataset) do
2475 sas.submit([[
2476 data _null_ ;
2477 RCO = open("@tag@") ;
2478 RC = attrn(RCO , "modte") ;
2479 CL = close(RCO) ;
2480
2481 format RC e8601dt. ;
2482 putlog "@tag@:" RC ;
2483 run ;
2484 ]])
2485
2486 end
2487
2488 endsubmit;
2489 run ;
NOTE: Lua initialized.
data _null_ ;
run ;
NOTE: DATAステートメント処理(合計処理時間):
処理時間 0.00 秒
CPU時間 0.00 秒
data _null_ ;
RCO = open("work.tst") ;
RC = attrn(RCO , "modte") ;
CL = close(RCO) ;
format RC e8601dt. ;
putlog "work.tst:" RC ;
run ;
work.tst:2019-01-12T20:01:32
NOTE: DATAステートメント処理(合計処理時間):
処理時間 0.01 秒
CPU時間 0.01 秒
data _null_ ;
RCO = open("work.tst1") ;
RC = attrn(RCO , "modte") ;
CL = close(RCO) ;
format RC e8601dt. ;
putlog "work.tst1:" RC ;
run ;
work.tst1:2019-01-12T20:01:32
NOTE: DATAステートメント処理(合計処理時間):
処理時間 0.00 秒
CPU時間 0.00 秒
data _null_ ;
RCO = open("work.tst2") ;
RC = attrn(RCO , "modte") ;
CL = close(RCO) ;
format RC e8601dt. ;
putlog "work.tst2:" RC ;
run ;
work.tst2:2019-01-12T20:01:32
NOTE: DATAステートメント処理(合計処理時間):
処理時間 0.00 秒
CPU時間 0.00 秒
NOTE: TKLua terminated.
NOTE: PROCEDURE LUA処理(合計処理時間):
処理時間 0.35 秒
CPU時間 0.20 秒
2019年2月13日水曜日
指定したライブラリのパスをログに表示する話
ライブラリのパスをログに表示させる話です.
pathname関数でパスの場所が取れるので,それをputlogしています.
どこのデータセットつかったのか,読み込んだデータが最新を格納している場所からちゃんと取れているのかを聞かれる時ありますから...
どうせログは保存するのだから,ログに出しておけば安心という考えです.
過剰な記録かもしれませんが...
以下にプログラムと実行ログおいておきます.
libname hoge "/home/xxxx/sasuser.v94/hoge" ;
/*---------- 指定したライブラリのパスをログに表示 ----------*/
data _null_ ;
V_PATH = pathname("hoge") ;
putlog "hoge:" V_PATH ;
run ;
/*---------- 実行ログ ----------*/
71 data _null_ ;
72 V_PATH = pathname("hoge") ;
73 putlog "hoge:" V_PATH ;
74
75 run ;
hoge:/home/xxxx/sasuser.v94/hoge
pathname関数でパスの場所が取れるので,それをputlogしています.
どこのデータセットつかったのか,読み込んだデータが最新を格納している場所からちゃんと取れているのかを聞かれる時ありますから...
どうせログは保存するのだから,ログに出しておけば安心という考えです.
過剰な記録かもしれませんが...
以下にプログラムと実行ログおいておきます.
libname hoge "/home/xxxx/sasuser.v94/hoge" ;
/*---------- 指定したライブラリのパスをログに表示 ----------*/
data _null_ ;
V_PATH = pathname("hoge") ;
putlog "hoge:" V_PATH ;
run ;
/*---------- 実行ログ ----------*/
71 data _null_ ;
72 V_PATH = pathname("hoge") ;
73 putlog "hoge:" V_PATH ;
74
75 run ;
hoge:/home/xxxx/sasuser.v94/hoge
2019年2月1日金曜日
データセットの更新日を取得する話
指定したデータセットの更新日を取得してログに表示します.
いつのどのデータセットつかって作業したか,を残しておいたほうがいいときに使っています.
どうせログは保存するのだから,ログに出しておいたら確認できるやろ,の精神ですね.
attrn関数のmodteを指定すると,更新日時が取れます.
指定を変えると作成日時も取れるらしいですがためしていません.
取れてきたものにe8601dtのフォーマットあててputlogしています.
いつのつかってたっけ?でドキッとすることがなくなるので便利なんですが,ここまで残す必要がある時があるかと言うと...微妙ですね...
以下にプログラムと実行時のログを残します.
sas studioで実行しています.製品版でも大差ないはずです.
/*---------- ライブラリ指定 ----------*/
libname hoge "/home/xxxx/sasuser.v94/hoge" ;
/*---------- 指定したデータの更新日をログに表示 ----------*/
data _null_ ;
RCO = open("hoge.card") ;
RC = attrn(RCO , "modte") ;
CL = close(RCO) ;
format RC e8601dt. ;
putlog "card:" RC ;
run ;
/*---------- 実行ログ ----------*/
71 data _null_ ;
72 RCO = open("hoge.card") ;
73 RC = attrn(RCO , "modte") ;
74 CL = close(RCO) ;
75
76 format RC e8601dt. ;
77 putlog "card:" RC ;
78 run ;
card:2018-01-22T13:15:42
いつのどのデータセットつかって作業したか,を残しておいたほうがいいときに使っています.
どうせログは保存するのだから,ログに出しておいたら確認できるやろ,の精神ですね.
attrn関数のmodteを指定すると,更新日時が取れます.
指定を変えると作成日時も取れるらしいですがためしていません.
取れてきたものにe8601dtのフォーマットあててputlogしています.
いつのつかってたっけ?でドキッとすることがなくなるので便利なんですが,ここまで残す必要がある時があるかと言うと...微妙ですね...
以下にプログラムと実行時のログを残します.
sas studioで実行しています.製品版でも大差ないはずです.
/*---------- ライブラリ指定 ----------*/
libname hoge "/home/xxxx/sasuser.v94/hoge" ;
/*---------- 指定したデータの更新日をログに表示 ----------*/
data _null_ ;
RCO = open("hoge.card") ;
RC = attrn(RCO , "modte") ;
CL = close(RCO) ;
format RC e8601dt. ;
putlog "card:" RC ;
run ;
/*---------- 実行ログ ----------*/
71 data _null_ ;
72 RCO = open("hoge.card") ;
73 RC = attrn(RCO , "modte") ;
74 CL = close(RCO) ;
75
76 format RC e8601dt. ;
77 putlog "card:" RC ;
78 run ;
card:2018-01-22T13:15:42
2019年1月24日木曜日
冬のSAS忘年会にいってきた話
12月21日,SASの発表会に行ってきた.
年末だけあって何分立て込んでいたがなんとか間に合う時間に退社し,いそいそと会場に向かう.
当日はあいにくの雨,ただでさえ寒いのにさらに冷えるのはほんと勘弁してもらいたい.
途中にある松屋で牛飯をかきこんでから会場に入る.松屋は牛丼ではない,牛飯です.
会場に入って待つことしばし,まあ来るわくるわ参加者が.途中から何人来るかの把握をあきらめていたが,やはり今回は多かった.全部で10人ちょっとか.
とりあえず椅子だけ並べて会長の100万回の管理人さんの挨拶を頂いて,さて皆で発表.
1人5分程度のライトニングセッションなのだがコレが気楽で良い.30分質疑込みとか重すぎてしんどいだけである.
グラフから始まり文字コードなどのバラエティに富んだ発表がたくさんだった.よくもまあそんなネタが出てくるもんである.
終わった後は飲み屋で串を食べ食べ他愛も無い話に花が咲く.私はお酒はダメなのでミックスジュースだった
気づくと終電の時間が近く,食べ過ぎの体に鞭打って駅に走りとても苦しかった.たまたま電車が遅れていたので終電に間に合い無事帰宅と相成った.
毎度場所の選定から飲み会のセットまでやってくださる方には頭が上がらない.
この場を借りて感謝をお伝えします.ありがとうございます.
そろそろ人数が増えてきたので,どこか良い感じの場所があるといいなあ,どこかに親切なS○S社とかいませんかね.
連絡手段もメールはそろそろ限界ですしなあ
年末だけあって何分立て込んでいたがなんとか間に合う時間に退社し,いそいそと会場に向かう.
当日はあいにくの雨,ただでさえ寒いのにさらに冷えるのはほんと勘弁してもらいたい.
途中にある松屋で牛飯をかきこんでから会場に入る.松屋は牛丼ではない,牛飯です.
会場に入って待つことしばし,まあ来るわくるわ参加者が.途中から何人来るかの把握をあきらめていたが,やはり今回は多かった.全部で10人ちょっとか.
とりあえず椅子だけ並べて会長の100万回の管理人さんの挨拶を頂いて,さて皆で発表.
1人5分程度のライトニングセッションなのだがコレが気楽で良い.30分質疑込みとか重すぎてしんどいだけである.
グラフから始まり文字コードなどのバラエティに富んだ発表がたくさんだった.よくもまあそんなネタが出てくるもんである.
終わった後は飲み屋で串を食べ食べ他愛も無い話に花が咲く.私はお酒はダメなのでミックスジュースだった
気づくと終電の時間が近く,食べ過ぎの体に鞭打って駅に走りとても苦しかった.たまたま電車が遅れていたので終電に間に合い無事帰宅と相成った.
毎度場所の選定から飲み会のセットまでやってくださる方には頭が上がらない.
この場を借りて感謝をお伝えします.ありがとうございます.
そろそろ人数が増えてきたので,どこか良い感じの場所があるといいなあ,どこかに親切なS○S社とかいませんかね.
連絡手段もメールはそろそろ限界ですしなあ
2019年1月1日火曜日
文字列の前後のスペースを除いてマクロ変数を作る話
たとえば" test"のような,マクロ変数にしたい文字列の前後に要らないスペースがある時,
スペースを取り除いてマクロ変数にすることがあると思います.
今回の例で言うと"test"と言う値をマクロ変数に格納する場合です.
そんな時はcall symputxが便利ですよ,と言う話です.
call symputxだと前後のスペースを取り除いてマクロ変数にしてくれます.
call symputx("a" , " test")と,call symput("a" , left(trim(" test") ))は同じです.
割と色んな場所で見かける紹介なのですが,あえてcall symputでマクロ変数を作っていてスペースを取り除き忘れたために
意図しない挙動を取ったプログラムを見かけたので私も紹介します.
/*---------- 以下マクロ変数作成時のプログラムの例 ----------*/
data _null_ ;
call symput("a1" , " test") ;
call symput("a2" , left(trim(" test") )) ;
call symputx("a3" , " test") ;
run ;
%put &=a1 ;
%put &=a2 ;
%put &=a3 ;
/*---------- 作成したマクロ変数をlogに表示 ----------*/
39
40 %put &=a1 ;
A1= test
41 %put &=a2 ;
A2=test
42 %put &=a3 ;
A3=test
スペースを取り除いてマクロ変数にすることがあると思います.
今回の例で言うと"test"と言う値をマクロ変数に格納する場合です.
そんな時はcall symputxが便利ですよ,と言う話です.
call symputxだと前後のスペースを取り除いてマクロ変数にしてくれます.
call symputx("a" , " test")と,call symput("a" , left(trim(" test") ))は同じです.
割と色んな場所で見かける紹介なのですが,あえてcall symputでマクロ変数を作っていてスペースを取り除き忘れたために
意図しない挙動を取ったプログラムを見かけたので私も紹介します.
/*---------- 以下マクロ変数作成時のプログラムの例 ----------*/
data _null_ ;
call symput("a1" , " test") ;
call symput("a2" , left(trim(" test") )) ;
call symputx("a3" , " test") ;
run ;
%put &=a1 ;
%put &=a2 ;
%put &=a3 ;
/*---------- 作成したマクロ変数をlogに表示 ----------*/
39
40 %put &=a1 ;
A1= test
41 %put &=a2 ;
A2=test
42 %put &=a3 ;
A3=test
2018年12月1日土曜日
日時分の文字値から日付をSAS日付で取り出す
"2018-11-15T10:45"の様な形式の日付の文字変数を,日付部分だけSAS日付に変換する時ってあると思います.
今の例で言うと,"2018-11-15T10:45"文字値を2018-11-15のSAS日付の変数に変えると言うだけです.
以下にプログラムと実行ログを載せているので他に書くこと無いのですが,SAS9.3以下だとおかしくなることがあります.
もともとの文字変数側のlengthが短いと正しくSAS日付に変換できないことがあるようです.
SAS9.4だとこんなことは無く何も気にしなくて大丈夫です.
/*---------- プログラム ----------*/
data HOGE ;
A = "2018-11-15T10:45" ; output ;
A = "2018-11--T10:45" ; output ;
run ;
data _null_ ;
set HOGE ;
if count(A , "-") = 2 then B = input(A,is8601da.) ;
else putlog A ;
format B yymmdd10. ;
putlog A B ;
run ;
/*---------- 実行log ----------*/
356
357 data HOGE ;
358 A = "2018-11-15T10:45" ; output ;
359 A = "2018-11--T10:45" ; output ;
360
361 run ;
NOTE: データセットWORK.HOGEは2オブザベーション、1変数です。
NOTE: DATAステートメント処理(合計処理時間):
処理時間 0.01 秒
CPU時間 0.00 秒
362
363 data _null_ ;
364 set HOGE ;
365 if count(A , "-") = 2 then B = input(A,is8601da.) ;
366 else putlog A ;
367
368 format B yymmdd10. ;
369 putlog A B ;
370
371 run ;
2018-11-15T10:45 2018-11-15 /*1レコード目をputlog*/
2018-11--T10:45 /*Aにハイフンが2個以上あるのでelse以下のputlog*/
2018-11--T10:45 . /*2レコード目をputlog*/
NOTE: データセットWORK.HOGEから2オブザベーションを読み込みました。
NOTE: DATAステートメント処理(合計処理時間):
処理時間 0.00 秒
CPU時間 0.00 秒
今の例で言うと,"2018-11-15T10:45"文字値を2018-11-15のSAS日付の変数に変えると言うだけです.
以下にプログラムと実行ログを載せているので他に書くこと無いのですが,SAS9.3以下だとおかしくなることがあります.
もともとの文字変数側のlengthが短いと正しくSAS日付に変換できないことがあるようです.
SAS9.4だとこんなことは無く何も気にしなくて大丈夫です.
/*---------- プログラム ----------*/
data HOGE ;
A = "2018-11-15T10:45" ; output ;
A = "2018-11--T10:45" ; output ;
run ;
data _null_ ;
set HOGE ;
if count(A , "-") = 2 then B = input(A,is8601da.) ;
else putlog A ;
format B yymmdd10. ;
putlog A B ;
run ;
/*---------- 実行log ----------*/
356
357 data HOGE ;
358 A = "2018-11-15T10:45" ; output ;
359 A = "2018-11--T10:45" ; output ;
360
361 run ;
NOTE: データセットWORK.HOGEは2オブザベーション、1変数です。
NOTE: DATAステートメント処理(合計処理時間):
処理時間 0.01 秒
CPU時間 0.00 秒
362
363 data _null_ ;
364 set HOGE ;
365 if count(A , "-") = 2 then B = input(A,is8601da.) ;
366 else putlog A ;
367
368 format B yymmdd10. ;
369 putlog A B ;
370
371 run ;
2018-11-15T10:45 2018-11-15 /*1レコード目をputlog*/
2018-11--T10:45 /*Aにハイフンが2個以上あるのでelse以下のputlog*/
2018-11--T10:45 . /*2レコード目をputlog*/
NOTE: データセットWORK.HOGEから2オブザベーションを読み込みました。
NOTE: DATAステートメント処理(合計処理時間):
処理時間 0.00 秒
CPU時間 0.00 秒
登録:
投稿 (Atom)