Archive for the ‘SQL’ Category

    はてなブックマーク - PostgreSQL IN句での複数条件指定
    このエントリーをはてなブックマークに追加

    もういくつも寝ないでお正月です!

    Fusic Advent Calender5回目、最多出場回数を獲得することになりました安元です。
    まだ確認してませんが、年末ジャンボが当たっているはずなので、
    当たったあかつきには来年は車を買いたいと思います!!

    基本的なIN句の利用方法

    SQLでIN句を使用したことはありますか?
    一致させたい条件をカンマ区切りで並べるだけで簡単便利に利用できますね。

    福問い合わせを利用する場合は以下のようになります

    IN句での複数条件指定

    さて、このIN句で複数条件指定できたら便利だと思いませんか?

    日本語で条件を表現すると基本的なINの条件は
    「安元 もしくは 納富 もしくは 浜崎 もしくは 渡辺」となりますね。

    複数条件が指定できるということは
    「安元で男 もしくは 納富で女 もしくは 浜崎で男 もしくは 渡辺で女」
    こんな条件指定ができるのです。

    ではSQLを見てみましょう。
    今回は副問い合わせでの書き方から

    簡単ですね!

    指定したいカラムをカンマ区切りで括弧でくくるだけです。
    副問い合わせの返り値も複数カラムがかえってくるように変更しています。

    注意点は、
    条件となるカラムの並び順と、帰ってくるカラムの並び順をそろえることです。

    では、副問い合わせではなく、値指定の場合はどうなるでしょうか?
    以下のようなSQLになります。

    見れば納得な感じかと思いますが、
    知らないと意外とかけないSQLです。

    利用することは少ないかもしれませんが、
    場合によっては2回に分けなきゃかけないSQLを1つにまとめることもできますので
    覚えておくときっと何かの役に立ちますよ!

    さて、12/1から始まり経営陣まで巻き込みました
    Fusic Advent Calender2010も、この投稿をもって本当にお開き!
    続きはまた来年のお楽しみ!(笑点 5代目円楽風に)

    Fusic技術者はじめ経営陣・営業・事務ともども
    来年も一丸となってがんばって参りますのでよろしくお願いいたします。

      はてなブックマーク - PostgreSQLで数え年計算
      このエントリーをはてなブックマークに追加

      まさかまさかの4回目。いま宝くじを買えば3億当確の安元です。
      最近肩こりがひどいので、昨日からピップマグネループつけてます。
      そちらのレビューはまた今度。ビバ!プラシーボ!!

      さて本題。
      最近めっきり聞くことも少なくなった「数え年」。皆さんご存じでしょうか?
      ウィキペディアさんに聞いてみました

      数え年(かぞえどし)とは年齢や年数の数え方の一つである。生まれた時点、基点となる最初の年を「1歳」、「1年」とし、以降元日(1月1日)を迎えるごとにそれぞれ1歳、1年ずつ加える(例:12月31日に出生した場合、出生時に1歳で翌日(1月1日)に2歳となる。また1月1日に出生した場合は、2歳になるのは翌年の1月1日になる)。数え歳とも、単に数えともいう。
      これに対し、誕生日前日午後12時に加齢、加年する数え方を満年齢、満という。本稿においては主に年齢に関する事柄について記述する。

      これ日本独自のものかと思ってましたが、アジア圏ではそれなりに使われているそうです。
      私が必要となった数え年は、「1月1日」での年齢加算ではなく
      「4月1日」での年齢加算でした。いかにも日本の企業で必要になりそうですね!

      年齢を計算してみましょう

      誕生日から一般的な年齢計算を行いましょう

      ここで一番大切なのは「1979-09-02」ですね!私の誕生日です!

      SELECT句の2行目
      age関数が返してくる値は経過年月日ですね。
      SELECT句の3行目
      age関数の結果から「年」だけを切り出したものこれが「満年齢」になります。

      1月1日で年齢を加算する

      数え年ということは、「1月1日」で年齢が加算されるということです。
      ということは、何月に生まれようとも誕生日を「1月1日」生まれにしてしまえば
      みんな一緒に歳をとれますね!

      SELECT句2行目が示すように、
      誕生日から年だけ切り出し「-01-01」を付け足すことで無理矢理「1月1日」に強制しています
      やや乱暴ですが、これで数え年はでました。

      4月1日で年齢を加算する

      では日本ではよく使う「4月1日」を基準に考える「年度」で歳を取りましょう。

      ここで問題になるのは1月〜3月生まれの人々です。
      先ほどのように全員「4月1日」生まれに強制してしまいたいのですが、単純に年を切り出すと
      1月〜3月生まれは1歳進んでしまいます。
      この3ヶ月が邪魔なので、みんな誕生日を3ヶ月巻き戻して考えてしまいましょう。
      3月生まれは前年の12月生まれに、4月生まれは同年1月生まれになりますね。
      これで年をそろえることができます。

      1920年8月生まれは90歳 3月生まれは91歳と差が出ているのがわかります。

      PostgreSQLでは、日付計算が「 + ’1months’」のように月単位や年単位での計算ができます。

      長々とSQLを書いてきましたが、システム内で頻繁に年度計算を利用する場合は
      関数化してSQLに組み込むと使い勝手がよくなるのでご検討ください。

      それでは肩がこってきたのでこの辺で。

        はてなブックマーク - 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式の活用を検討してみるといいことがあるかもしれません。