早速、PostgreSQL 8.4の新機能を見ていくことにしましょう。
インストール方法については、PostgreSQLユーザ会のWebサイト等に詳しいドキュメントがありますので割愛。8.4ベータも、従来のバージョンとインストール方法は変化ありません。基本的にはソースコードを入手してconfigure; make; make installするだけなので簡単ですが、一点だけ、root権限でインストールを実行しないように注意しましょう。データディレクトリがrootの所有になっていると、データベースクラスタの初期化(initdb)を正しく行うことができません。
では、まず追加された便利な機能から紹介していきましょう。最初は「Window関数による集計機能の強化」です。「Window関数」は、簡単に言うと「複雑なデータ分析要求に迅速に答える」ための機能のひとつです。例えば、BI(ビジネスインテリジェンス)の分野では膨大なデータを分析することで新たな知識発見を試みますが、単純な検索・集計機能だけでは、分析に多大な時間と労力が必要になってしまいます。
Window関数を使うと、テーブルのデータを特定の列の値でグルーピングし、各グループ毎の「順位」や「全体に占める割合」などを簡単に取得できます。SQLには「GROUP BY」もありますが、「GROUP BY」ではグルーピングした行が1行に集約されてしまうのに対し、Window関数では元の行をそのまま取得できる点で、より柔軟な使い方が可能になります。これまで頭を捻って無理矢理なSQLを書いていたような処理も、スマートかつ効率的に書けるようになる、というわけです。言葉だけではなかなかイメージしづらいと思いますので、実例を挙げて説明しましょう。
ここでは例として、Web上に「○○検定」の簡単な検定フォームを設置したと想定し、その結果を格納するためのテーブル「exam」を一つ用意します。
create table exam (
id integer primary key, -- ID
name text, -- 名前
country text, -- 国
city text, -- 都市
email text, -- メールアドレス
point integer -- 得点
);
このテーブルには、適当なテストデータを格納しておきます。テストデータを自分で作成するのは大変なので、今回はGENERATEDATA.COMのサービスを使って生成した、200件のランダムなデータを利用します。データの内容はこんな感じ。
-[ RECORD 1 ]-------------------------------------------------
id | 1
name | Cheryl Vincent
country | United Kingdom
city | Elkhart
email | neque.vitae@netuset.org
point | 53
-[ RECORD 2 ]-------------------------------------------------
id | 2
name | Althea Mayer
country | Macao
city | Modesto
email | pede.Nunc@Vivamussit.ca
point | 59
-[ RECORD 3 ]-------------------------------------------------
id | 3
name | Karleigh Reed
country | Belize
city | Muncie
email | aliquam.adipiscing.lacus@parturientmontesnascetur.ca
point | 70
:
:
例えば国別の得点順位表が欲しい場合、Window関数を使うと以下のような問い合わせを記述できます。
select country, name, point, rank() over (partition by country order by point desc) from exam;
この問い合わせを実行してみたところ、以下の結果が返りました。 マカオ、マレーシアといった国別に、得点上位から順位が1,2,3と振られているのがわかりますね。
:
Macao | Althea Mayer | 59 | 1
Macao | Rhonda Hutchinson | 52 | 2
Macao | Ashely Sheppard | 21 | 3
Macedonia | Zoe Brock | 94 | 1
Malawi | Clementine Deleon | 96 | 1
Malawi | Courtney Weeks | 57 | 2
Malaysia | Briar Griffith | 100 | 1
Malaysia | Aretha Walsh | 87 | 2
Malaysia | Briar Humphrey | 43 | 3
:
:
先ほどの問い合わせでは、Window関数「rank()」を使用していますが、関数自体よりも重要なのはむしろ「OVER」句でしょう。「partition by country(国で区切れ)」「order by point desc(得点の降順で並び替えろ)」といった条件をOVERで指定することで、rank()関数は区切られた範囲内の順位を集計してくれるわけです。
PostgreSQL 8.4では、rank()の他にもいくつかのWindow関数が用意されています。
関数名 | 処理 |
---|---|
row_number() | 区間内での行番号を返します |
rank() | 順位(同位がある場合、次点は番号が飛ぶ)を返します |
dense_rank() | 順位(同位がある場合でも、次点は番号が飛ばない)を返します |
percent_rank() | 順位(割合-%で表示)を返します |
cume_dist() | 区間内での相対的な位置を返します |
ntile(N) | N分位数に分割 ※ Nに3を指定すると、1位~6位までを1,2,3,1,2,3のように1~3位の繰り返しで返します |
lag(value, offset, default) | 区間内でoffsetで指定された行数分だけ前の行の、valueに指定された列の値を返します。指定された行が存在しなければdefaultに指定した値を返します |
lead(value, offset, default) | 区間内でoffsetで指定された行数分だけ後の行の、valueに指定された列の値を返します。指定された行が存在しなければdefaultに指定した値を返します |
first_value(value) | 区間内でvalueに指定された列の最初の値を返します |
last_value(value) | 区間内でvalueに指定された列の最後の値を返します |
nth_value(value any, N) | 区間内でvalueに指定された列のN番目の値を返します |
最近はWebアプリでも、顧客からいろいろな統計、分析機能を要求されることが増えています。Window関数を上手く使いこなせば、「CSV出力するからExcelでやって!」なんて逃げなくてもすむようになるかもしれませんね。