SQL PARTITION BYで効率よくデータを取得する
SQL OVER句の分析関数で効率よくデータを集計するで分析関数を使って効率よくデータを集計する方法を紹介しましたが、PARTITION BY
をうまく使用すれば、効率よく簡単にデータを集計だけでなく、取得することができます。
例えば、以下のようなデータがあるとします。(実際にはこのようなテーブル構成は考えにくいですが、わかりやすくするためにこのような例にしています。副問い合わせの結果や、VIEWなどで以下のテーブルを取得したと考えてください)
部署コード | 部署名 | 社員コード | 社員名 | 年月 | 売上金額 |
---|---|---|---|---|---|
1 | 営業部 | 1 | テスト社員1 | 201501 | 500 |
1 | 営業部 | 1 | テスト社員1 | 201502 | 1500 |
2 | 開発部 | 2 | テスト社員2 | 201501 | 100 |
2 | 開発部 | 2 | テスト社員2 | 201502 | 1000 |
2 | 開発部 | 3 | テスト社員3 | 201501 | 200 |
2 | 開発部 | 3 | テスト社員3 | 201502 | 100 |
2 | 開発部 | 4 | テスト社員4 | 201501 | 2000 |
2 | 開発部 | 4 | テスト社員4 | 201502 | 1000 |
1 | 営業部 | 5 | テスト社員5 | 201501 | 1500 |
1 | 営業部 | 5 | テスト社員5 | 201502 | 2000 |
部署ごとに、売上金額の合計が一番多い社員を表示したい。
SQL
は下記のようになります。
SELECT
URI2.部署名
,URI2.社員名
,URI2.売上累計
FROM (
SELECT
URI1.部署名
,URI1.社員名
,URI1.売上累計
,ROW_NUMBER() OVER(PATITION BY URI1.部署コード ORDER BY URI1.売上累計 DESC, URI1.社員コード) 売上ランク
FROM (
--部署、社員、ごとに売上金額の合計を取得します
SELECT
T1.部署コード
,T1.部署名
,T1.社員コード
,T1.社員名
,SUM(T1.売上金額) AS 売上累計
FROM
売上結果 T1
GROUP BY
T1.部署コード
,T1.部署名
,T1.社員コード
,T1.社員名
) URI1
) URI2
WHERE
URI2.売上ランク = 1
部署名 | 社員名 | 売上累計 |
---|---|---|
営業部 | テスト社員5 | 3500 |
開発部 | テスト社員4 | 3000 |
URI1
を取得する副問い合わせは、年月ごとにあるデータを、グループ化して、社員ごとに全期間の売上の合計を取得しています。
部署コード | 部署名 | 社員コード | 社員名 | 売上金額 |
---|---|---|---|---|
1 | 営業部 | 1 | テスト社員1 | 2000 |
2 | 開発部 | 2 | テスト社員2 | 1100 |
2 | 開発部 | 3 | テスト社員3 | 300 |
2 | 開発部 | 4 | テスト社員4 | 3000 |
1 | 営業部 | 5 | テスト社員5 | 3500 |
営業部で一番売上が多いのはテスト社員5、開発部ではテスト社員4なので、この2社員だけ取得する必要があります。
URI2
を取得する副問い合わせの結果は以下のようになります。
部署名 | 社員名 | 売上金額 | 売上ランク |
---|---|---|---|
営業部 | テスト社員1 | 2000 | 2 |
開発部 | テスト社員2 | 1100 | 2 |
開発部 | テスト社員3 | 300 | 3 |
開発部 | テスト社員4 | 3000 | 1 |
営業部 | テスト社員5 | 3500 | 1 |
ROW_NUMBER() OVER(PATITION BY URI1.部署コード DESC ORDER BY URI1.売上累計, URI1.社員コード)
で、部署コードごとに売上累計の降順で行番号を取得しています(売上累計が同じ場合は社員コードの昇順に取得しています)。
PATITION BY URI1.部署コード
で部署コード単位で集計することができるようになります。
売上累計の降順で並び替えたときの1行目が売上累計が最大のデータということになります。
よって、URI2テーブルをWHERE
句で売上ランク=1
で絞り込むと、部署ごとに売上累計が最大の社員のデータのみ取得することができます。