proc sqlの第7回目はcase式です。
SASにも同じ機能のステートメントが存在しますが、sql上で使用すると超便利になりますので絶対押さえておくべき構文です。
CASE式について
SQLで条件分岐,、すなわち条件に応じて格納する値を変える場合はCASE文を使用します。
sasのselectステートメントと同じ機能を有します。やっていることは値の読み替えです。
条件式を定義する検索CASE式のほうが使用頻度高いので、ここではこちらを取り上げます。
case
when 条件式1 then 値1
when 条件式2 then 値2
else 値3
end as フィールド名
elseはなくても動作しますが、意図しないデータが入ってきた場合に気付けるようにかならずelseは追加しましょう。
これだけだとSASと同じじゃないかと思われるかもしれませんが、SQLとCASE式の組み合わせは色々利点があります。
活用例を用いてご紹介しましょう。
活用例
CASE式はSASのselectステートメントと同様なので、特定の条件に合致した場合にコード値やフラグを付与することができます。
では特定の条件に合致したレコード数を数えるにはどうしたらよいでしょう?
SASですと特定の条件に合致したレコードにフラグをたてて、proc freqで集計する方法が一般的かと思います。
SQLではCASE文を使うとSASよりも可読性が高いコードで実現できます。
前回の記事で特定の期間に該当するレコードをカウントするときにSASのデータステップを使いましたが、レコードのカウントもSQLで実施してみます。
データステップで該当するレコードをカウントする場合
proc sql noprint;
create table count_data as
select interval.*,
adlb.lbdt
from interval cross join adlb
where interval.usubjid=adlb.usubjid
order by usubjid, seq, lbdt;
quit;
data count1;
set count_data;
by usubjid seq;
retain lbcount;
if first.seq then lbcount=0;
*期間内のlbdtをカウントアップ;
if stdt<=lbdt<=endt then lbcount+1;
if last.seq;
keep usubjid seq lbcount;
run;
SQLとCASE式で該当するレコードをカウントする場合
proc sql noprint;
create table count2 as
select usubjid,
seq,
count(case when stdt<=lbdt<=endt then 1 else . end) as lbcount
from (
select interval.*,
adlb.lbdt
from interval cross join adlb
where interval.usubjid=adlb.usubjid
)
group by usubjid, seq
order by usubjid, seq;
quit;
CASE式と要約統計量関数を併用することで特定の条件に合致するレコードから要約統計量を算出できます。
上記の例ですと、サブクエリで集計用テーブルを用意し、CASE式で条件に合致したレコードの場合は1, しなかったレコードの場合は欠損値を代入しておき、それをcount関数でカウントします。
count関数は欠損値はカウントしませんので、条件に合致したレコードのみカウントされる仕組みです。
SASの場合はいったんデータセットをソートしてretainステートメントで集計結果を格納する変数を用意する手間が発生します。proc freqで集計する場合も複数のカウント結果を求めたい場合はちょっとめんどくさいと思います。
それに対しSQLはレコード数のカウントが1文で実現できるので可読性は高く、他の条件に合致するレコードのカウントを追加することも簡単です。