SAS

Proc sqlを極める(7) ーCASE式ー

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を極める(6) ーCross joinーproc sqlの第6回目です。今回はCross joinについてです。cross joinはmergeステートメントではできないので、...

データステップで該当するレコードをカウントする場合

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文で実現できるので可読性は高く、他の条件に合致するレコードのカウントを追加することも簡単です。