目次
PARTITION BYとは?

PARTITION BYとは、指定した列の値ごとに計算処理をする機能のことです。
「部門ごとの件数を付けたい」や「商品ごとにランクを付けたい」などの処理を行いたい場合に、PARTITION BYが使用されます。
分析関数や分析関数とあわせて使われるOVER句と一緒に、PARTITION BYも使うことが多いです。
分析関数とは?

「そもそも分析関数って何?」と思う人もいるでしょう。
分析関数とは、グループの中で指定された範囲を集計し、集計結果を各行に戻す関数のことです。
SQLの中でも分析関数は比較的新しく追加された機能であり、ウィンドウ(Window)関数とも言われます。
分析関数では、サブクエリーをいくつか組み合わせる必要があったものが、より簡単なSQL文で実現可能になりました。
分析関数の中で、PARTITION BYは列を指定するために用います。
分析関数でPARTITION BYを使う例
ここでは、分析関数でPARTITION BYを使う例を紹介します。
次のクエリでは、PARTITION BYとORDER BYを用いてNAMEごとにPRICEが大きい順に順番をつけます。
SELECT id, name, price,
ROW_NUMBER() OVER (PARTITION BY name ORDER BY price DESC)
FROM my_table;
ID NAME PRICE ROW_NUMBER()OVER(PARTITIONBYNAMEORDERBYPRICEDESC)
---------- ---------- ---------- -----------------------------------------------
1 Satou 570 1
3 Satou 440 2
2 Satou 200 3
5 Satou 80 4
6 Abe 350 1
4 Abe 130 2
上記のように、NAMEごとにPRICEが大きい順番で表示できます。
指定方法を少し工夫して、各NAMEごとに最大のPRICEをもつ行を取得するクエリも作成できます。
そのやり方は「PARTITION BYとWHEREを使って、最大値をもつ行を抜き出す」で解説しますね。
OVER句の基本的な使い方

先ほどの分析関数の例で「OVER句」を使用しました。
ここでは、OVER句について解説します。
OVER句では次の3つの方法を用いて、集計対象の範囲を指定できます。
・PARTITION BY
・ORDER BY
・WINDOW(Frame)
分析関数でOVER句を使う場合は、次のように指定しましょう。
OVER (PARTITION BY 集計単位 ORDER BY 表示順)
PARTITION BYが集計したい列を指定するのに対して、ORDER BYは表示順を指定します。
先ほどの例でも使用した「ROW_NUMBER(行番号)」など、集計結果を並び替えたい場合に使うことが多いです。
WINDOWは、ORDER BYのオプションのような扱いです。
行をソートした際に、各行でどこからどこまでを集計の対象にするかを指定できます。
そのため、WINDOWを指定する場合は必ずORDER BYが必要です。
ORDER BYでは先頭行から現在行までが対象範囲になりますが、これはWINDOWを省略した場合のデフォルト動作になっています。
それをWINDOWを使うことで、対象範囲を自由に設定可能です。
ただし、分析関数によってはWINDOWが使えない関数もあるため、マニュアルで確認が必要になります。
PARTITION BYとSUMを使って、累計を求める

ここでは、PARTITION BYとSUMを使ってNAMEごとにPRICEの累計を求めてみましょう。
次のようにクエリを記述します。
SELECT id, name, price,
SUM(price) OVER (PARTITION BY name ORDER BY price DESC)
FROM my_table;
ID NAME PRICE SUM(PRICE)OVER(PARTITIONBYNAMEORDERBYPRICEDESC)
---------- ---------- ---------- -----------------------------------------------
1 Satou 570 570
3 Satou 440 1010
2 Satou 200 1210
5 Satou 80 1290
6 Abe 350 350
4 Abe 130 480
PARTITION BYによってNAMEでグルーピングされ、ORDER BYによって順序が決まって累計されています。
PARTITION BYとWHEREを使って、最大値をもつ行を抜き出す
「分析関数でPARTITION BYを使う例」で少し説明したように、分析関数を使うことでグループ内の最大値や最小値など特定の行を抜き出せます。
ここでは、PARTITION BYとWHEREを使って、最大値をもつ行を抜き出してみましょう。
最大値をもつ行を抜き出すには、次のようにクエリを記述します。
SELECT * FROM (
SELECT id, name, price,
ROW_NUMBER() OVER (PARTITION BY name ORDER BY price DESC) rn
FROM my_table)
WHERE rn = 1;
ID NAME PRICE RN
---------- ---------- ---------- ----------
1 Satou 570 1
6 Abe 350 1
NAMEごとにRN=1(最大値)の行が抜き出せました。
PARTITION BYとRANKを使って、ランク付けする

ここでは、PARTITION BYとRANKを使って、ランク付けするクエリを見ていきましょう。
RANKは、結果セットに順位を付ける関数です。構文はROW_NUMBER と同じになります。
ROW_NUMBERは各行に異なる番号を振るのに対し、RANKは列の値が同じだった場合には同じ番号が振られます。
実際にクエリを書いてみましょう。
SELECT name, age, gender
ROW_NUMBER() OVER (PARTITION BY gender ORDER BY age DESC) AS RowNo,
RANK() OVER (PARTITION BY gender ORDER BY age DESC) AS RankNo,
FROM my_table;
NAME AGE GENDER ROWNO RANKNO
---------- ---------- ---------- ---------- ----------
Akio 45 M 1 1
Tarou 32 M 2 2
Daichi 32 M 3 2
Masaki 31 M 4 4
Hanako 29 F 1 1
Yuki 24 F 2 2
GENDERごとにわけて年齢が高い順に順位付けされています。
また、RANKNOは同じ年齢(32)の場合は両方とも同じ番号が振られており、3はスキップされています。
PARTITION BYとGROUP BYの違い

SQLの中で「グループ分けの機能」をもっている句が、「GROUP BY」と「PARTITION BY」です。
両者はテーブルを指定されたキーで分割する働きがあります。
そんな2つで異なる点が、GROUP BYの場合は「分割後に集約して、1行にまとめる」操作が入ることです。
それ以外の点は同じですので、覚えておきましょう。
まとめ

SQLのPARTITION BYについて解説しました。
PARTITION BYは、指定した列の値ごとに計算処理ができ、分析関数と併用することで効率よくデータを取得できます。
ぜひこの記事を参考に、PARTITION BYの使い方をマスターしてください!