{ 2010.12.14 }

PostgreSQLでCase式とGroup化

    はてなブックマーク - PostgreSQLでCase式とGroup化
    このエントリーをはてなブックマークに追加

    まさか3度目は無いだろうと完全に油断していた。。。。
    Advent Calendar3度目の登場の安元です。
    年末ジャンボを買うなら今だ!と無責任にけしかける社員がいっぱいる楽しい会社です。

    さて、前回、前々回とSQLについて書いております。今回も趣向も変えずにSQLです。
    PHPでもRubyでもフレームワークを利用されることがほとんどで
    「SQLなんて書かねーよ!!」というかたも多いのではないでしょうか?

    弊社でもフレームワーク導入の前後ではSQLに携わる機会は激減しているのが現状です。
    しかし業務系のシステムでは、集計や統計を必要とすることがよくありますので、
    「SQLでデータまとめる」という選択肢を持っておくと、プログラムがぐっとシンプルになることもあります。

    というわけで、今回はGroup ByとCase式を絡めて利用してみましょう。

    年齢ごとの集計

    今回利用するのは以下のようなテーブルです
    性別と誕生日が格納されているシンプルなテーブル構成です。
    実務ではユーザーテーブルなんかでよくある構成ですね。
    レコード数は全部で3525件準備しました。

    
     id | sex |  birthday
    ----+-----+------------
      1 | f   | 1920-08-08
      2 | f   | 1927-07-28
      3 | f   | 1920-03-28
      4 | f   | 1921-03-21
      5 | f   | 1913-12-23
    (10 rows)
    

    まずはシンプルに年齢ごとの集計をとってみましょう
    (12月1日時点での年齢をもとに集計します)

    これで「年齢」ごとの集計はできました。
    しかし実務では、「年齢」ごとの集計では情報の粒度が細かすぎることが多いです。

    年代ごとの集計

    では、10代・20代のように年代ごとの集計をしてみましょう。
    使うのは、Case式です。
    まずはSQLを見てみましょう

    特徴的なのは、
    SELECT句の最初のCase式で条件分けをしていることと
    COUNT関数の中でのCase式の利用いる部分ですね

    SELECT句のCase式はGROUP BYにも書くことができますが、
    SELECT句に先に記述し「AS」で別名を付けることで、
    GROUP BY、ORDERともに別名を利用でき、SQLを短くすることができます。

    Case式の中でやっていることは年齢を年代に置き換える作業です

    date_part('year', age('2010-12-1',birthday)) between 1 and 19 then 10

    分解してみましょう
    1:age関数を利用して、誕生日からの経過年・月・日が取得できます

    age('2010-12-1',birthday)

    2:取得した年月日から、年だけを取得します。これが年齢になりますね

    date_part('year', age('2010-12-1',birthday))

    3:最後にbetweenを利用して、「年代」に置き換えています

    case
    when date_part('year', age('2010-12-1',birthday)) between 1 and 19 then 10
    end

    このようにCase式を使うと、「条件に一致する複数のデータを一つのデータにまとめ直す」ことができるのが大きな利点です。

    性別・年代ごとの集計

    それでは最後に、先ほどの年代別の集計を性別ごとに分けてみましょう。
    問い合わせ結果が横に伸びるということは、SELECT句の項目が増えることになります。
    今回はシンプルにCase式の各条件に性別条件を付加しました

    結果はこのようになります

    age_group | men | women
    -----------+-----+-------
    20 | 0 | 1
    30 | 14 | 192
    40 | 45 | 663
    50 | 56 | 905
    60 | 47 | 743
    70 | 9 | 367
    80 | 21 | 278
    90 | 4 | 141
    100 | 1 | 36
    (9 rows)

    とてもシンプルな結果が返ってきました。
    Case式は応用の幅が広いです。
    思いもつかなかった活用法がWEB紹介されていることもありますから、
    集計に行き詰ったら、Case式の活用を検討してみるといいことがあるかもしれません。

    Comments are closed.