Window関数の基本について学びました
記事を書くきっかけ
学習した内容を整理するために本記事を書きました。
ゴール
Window関数について学んだことを整理することで知識を定着させる。
学習した内容
こちらのサイトでWindows関数についての基本を学びました。
Window関数とは
上に示したサイトでは、次のような説明がありました。
Window関数は、一連のクエリー行に対して集計のような操作を実行します。 ただし、集計操作ではクエリー行が単一の結果行にグループ化されますが、ウィンドウ関数ではクエリー行ごとに結果が生成されます。
例を見るとイメージがつかみやすいと思いました。
つぎのようなデータを持ったsalesテーブルがあるとします。
mysql> SELECT * FROM sales ORDER BY country, year, product;
+------+---------+------------+--------+
| year | country | product | profit |
+------+---------+------------+--------+
| 2000 | Finland | Computer | 1500 |
| 2000 | Finland | Phone | 100 |
| 2001 | Finland | Phone | 10 |
| 2000 | India | Calculator | 75 |
| 2000 | India | Calculator | 75 |
| 2000 | India | Computer | 1200 |
| 2000 | USA | Calculator | 75 |
| 2000 | USA | Computer | 1500 |
| 2001 | USA | Calculator | 50 |
| 2001 | USA | Computer | 1500 |
| 2001 | USA | Computer | 1200 |
| 2001 | USA | TV | 150 |
| 2001 | USA | TV | 100 |
+------+---------+------------+--------+
このテーブルに対して、COUNTやMAXやSUMなど通常の集約関数を利用した場合の例をつぎに示します。
例の上のクエリでは、profitをひとつのグループとして集約した値が出力されています。
例の下のクエリでは、countryごとにprofitをグループとして集約した値が出力されています。
mysql> SELECT SUM(profit) AS total_profit
FROM sales;
+--------------+
| total_profit |
+--------------+
| 7535 |
+--------------+
mysql> SELECT country, SUM(profit) AS country_profit
FROM sales
GROUP BY country
ORDER BY country;
+---------+----------------+
| country | country_profit |
+---------+----------------+
| Finland | 1610 |
| India | 1350 |
| USA | 4575 |
+---------+----------------+
Window関数を利用した場合の例をつぎに示します。この場合はレコードごとに結果が出力されます。
mysql> SELECT
year, country, product, profit,
SUM(profit) OVER() AS total_profit,
SUM(profit) OVER(PARTITION BY country) AS country_profit
FROM sales
ORDER BY country, year, product, profit;
+------+---------+------------+--------+--------------+----------------+
| year | country | product | profit | total_profit | country_profit |
+------+---------+------------+--------+--------------+----------------+
| 2000 | Finland | Computer | 1500 | 7535 | 1610 |
| 2000 | Finland | Phone | 100 | 7535 | 1610 |
| 2001 | Finland | Phone | 10 | 7535 | 1610 |
| 2000 | India | Calculator | 75 | 7535 | 1350 |
| 2000 | India | Calculator | 75 | 7535 | 1350 |
| 2000 | India | Computer | 1200 | 7535 | 1350 |
| 2000 | USA | Calculator | 75 | 7535 | 4575 |
| 2000 | USA | Computer | 1500 | 7535 | 4575 |
| 2001 | USA | Calculator | 50 | 7535 | 4575 |
| 2001 | USA | Computer | 1200 | 7535 | 4575 |
| 2001 | USA | Computer | 1500 | 7535 | 4575 |
| 2001 | USA | TV | 100 | 7535 | 4575 |
| 2001 | USA | TV | 150 | 7535 | 4575 |
+------+---------+------------+--------+--------------+----------------+
通常の集約関数ではグループごとに単一の結果が出力されますが、Window関数ではレコードごとに結果が出力されます。
Window関数の構文
Window関数の基本的な構文はつぎのようになります。
<Window関数> OVER (PARTITION BY col_name1 ORDER BY col_name2)
col_name1の部分には、順位付けを行う対象の範囲を指定します。
col_name2の部分には、順位付けを行う列を指定します。
Window関数の使用例
つぎに、Window関数の使用例を示します。今回はつぎの3つのWindow関数を使用してみます。
RANK():パーティション内の現在の行のランク (ギャップあり)
DENSE_RANK():パーティション内の現在の行のランク (ギャップなし)
ROW_NUBER():パーティション内の現在の行数
mysql> SELECT
year, country, product, profit,
RANK() OVER(PARTITION BY country ORDER BY profit DESC) AS ranking,
DENSE_RANK() OVER(PARTITION BY country ORDER BY profit DESC) AS dense_ranking,
ROW_NUMBER() OVER(PARTITION BY country ORDER BY profit DESC) AS row_num
FROM sales;
+------+---------+------------+--------+---------+---------------+---------+
| year | country | product | profit | ranking | dense_ranking | row_num |
+------+---------+------------+--------+---------+---------------+---------+
| 2000 | Finland | Computer | 1500 | 1 | 1 | 1 |
| 2000 | Finland | Phone | 100 | 2 | 2 | 2 |
| 2001 | Finland | Phone | 10 | 3 | 3 | 3 |
| 2000 | India | Computer | 1200 | 1 | 1 | 1 |
| 2000 | India | Calculator | 75 | 2 | 2 | 2 |
| 2000 | India | Calculator | 75 | 2 | 2 | 3 |
| 2000 | USA | Computer | 1500 | 1 | 1 | 1 |
| 2001 | USA | Computer | 1500 | 1 | 1 | 2 |
| 2001 | USA | Computer | 1200 | 3 | 2 | 3 |
| 2001 | USA | TV | 150 | 4 | 3 | 4 |
| 2001 | USA | TV | 100 | 5 | 4 | 5 |
| 2000 | USA | Calculator | 75 | 6 | 5 | 6 |
| 2001 | USA | Calculator | 50 | 7 | 6 | 7 |
+------+---------+------------+--------+---------+---------------+---------+
上記の例では、countryごとに、profitの降順でランキングと連番を生成しています。
- rankingでは同じ順位が存在した場合に、後続の順位が飛んでいる。
- dense_rankingでは同じ順位が存在した場合に、後続の順位が飛んでいない。
- row_numではcountryごとに連番が生成されている。
以上のことが確認できた。
まとめ
こちらのサイトでWindow関数について学びました。Window関数の概要と通常の集約関数との違いを確認したあとに、Window関数の基本的な構文について学びました。最後に、自分でWindow関数を使用して動きを確認しました。
Discussion