DS2ハッシュパッケージのdataset指定にSQL文書けるのは便利すぎるという話

DS2ではsetステートメントに set { SQL文 }; っていう書き方が通るという話は何回もしてます。
(正確にはFEDSQLプロシジャで使用できるSQL文)

それだけでも結構すごいことだと思いますが、個人的に一番助かったというか、感激したのはハッシュテーブルのdataset指定の部分にSQL入れれるってことなんですね。待ってましたよこの機能!

たとえば以下の2つのデータセットがあるとします。

data Q1;
ID=1;SEX='M';VAL=10;output;
ID=2;SEX='F';VAL=.;output;
ID=3;SEX='F';VAL=15;output;
ID=4;SEX='M';VAL=.;output;
run;










data Q2;
ID='A';SEX='M';VAL=10;output;
ID='B';SEX='M';VAL=14;output;
ID='C';SEX='M';VAL=13;output;
ID='D';SEX='M';VAL=15;output;
ID='E';SEX='F';VAL=9;output;
ID='F';SEX='F';VAL=8;output;
ID='G';SEX='F';VAL=11;output;
ID='H';SEX='F';VAL=16;output;
run;
















最初のデータセットQ1についてVALが欠損の箇所がありますが、
ここを後のデータセットQ2で算出した性別ごとの平均値を使って補完したいとします。

正道で行くならDS2をmeansプロシジャでも何でもつかって性別と平均値のテーブル作って、
結合して処理でしょう。最低2ステップは必要になります。

1ステップでやるなら、ひとつはハッシュオブジェクトですが、詳細は割愛しますが結構面倒になります。
まあ、実はこの程度であればSQLで普通にかけるんですが、それも今回は置いておきましょう。

DS2プロシジャのハッシュパッケージだと、以下のように

proc ds2 libs=work;
data OUT1(overwrite=yes);
declare package hash h1();
declare double ID mean;
drop mean;
method init();
h1.dataset('{select SEX,mean(VAL) as mean from Q2 group by SEX}');
h1.keys([SEX]);
h1.data([mean]);
h1.definedone();
end;
method run();
set Q1;
h1.find();
if VAL=. then VAL=mean;
end;
enddata;
run;
quit;










余計なデータセットも作らずに1ステップで完了です。
ミソはh1.dataset('{select SEX,mean(VAL) as mean from Q2 group by SEX}'); の部分ですね
SQLの結果がそのままデータセットとしてみなされているわけですね。

以下は、まだ未解決の問題なんですが、これが例えばQ1の平均でQ1を補完するみたいな場合、
Q1を2重に開けなくて、つまりロック状態でエラーになるんですね。
データセットオプションにlocktable=shareっていうのが指定できるみたいなんですが、それをSQLで
指定しているQ1に適用するのってどうやるのかな??
誰か知っていたら教えて下さいな。

それができればさらに便利なんだけど




1 件のコメント:

  1. いつも拝見させて頂いております。
    業務で同じ壁にぶつかり解決しましたので,共有させて頂きます。
    Q1を2重に開くには,以下のようにすることで実現できました。
    なぜか,2箇所で指定する必要がありました。

    if 0 then set Q1 (locktable=share);
    h1.dataset('{ select ... from Q1 {options locktable=share} }');

    よろしくお願いいたします。

    返信削除