MySQL8.
なお、
WINDOW関数を触ってみる
WINDOW関数を利用すれば通常、
まずは例を見てみましょう。worldデータベースのcityテーブルから、
mysql> SELECT CountryCode, sum(Population), avg(Population) FROM city GROUP BY CountryCode ORDER BY CountryCode; +-------------+-----------------+-----------------+ | CountryCode | sum(Population) | avg(Population) | +-------------+-----------------+-----------------+ | ABW | 29034 | 29034.0000 | | AFG | 2332100 | 583025.0000 | | AGO | 2561600 | 512320.0000 | (以下省略)
これをWINDOW関数を利用して出力してみます。
mysql> SELECT CountryCode, sum(Population) OVER(PARTITION BY CountryCode) as sum_population, avg(Population) OVER(PARTITION BY CountryCode) as avg_population FROM city ORDER BY CountryCode limit 20; +-------------+----------------+----------------+ | CountryCode | sum_population | avg_population | +-------------+----------------+----------------+ | ABW | 29034 | 29034.0000 | | AFG | 2332100 | 583025.0000 | | AFG | 2332100 | 583025.0000 | | AFG | 2332100 | 583025.0000 | | AFG | 2332100 | 583025.0000 | | AGO | 2561600 | 512320.0000 | | AGO | 2561600 | 512320.0000 | | AGO | 2561600 | 512320.0000 | | AGO | 2561600 | 512320.0000 | | AGO | 2561600 | 512320.0000 | (以下省略)
同じCountryCodeが複数回出力される結果になってしまいました。
今度はこの出力結果にDistrictカラムを追加して出力してみましょう。
mysql> SELECT CountryCode,District, sum(Population) OVER(PARTITION BY CountryCode) as sum_population, avg(Population) OVER(PARTITION BY CountryCode) as avg_population FROM city ORDER BY CountryCode limit 20; +-------------+------------------+----------------+----------------+ | CountryCode | District | sum_population | avg_population | +-------------+------------------+----------------+----------------+ | ABW | – | 29034 | 29034.0000 | | AFG | Balkh | 2332100 | 583025.0000 | | AFG | Kabol | 2332100 | 583025.0000 | | AFG | Qandahar | 2332100 | 583025.0000 | | AFG | Herat | 2332100 | 583025.0000 | | AGO | Benguela | 2561600 | 512320.0000 | | AGO | Luanda | 2561600 | 512320.0000 | | AGO | Namibe | 2561600 | 512320.0000 | | AGO | Huambo | 2561600 | 512320.0000 | | AGO | Benguela | 2561600 | 512320.0000 | (以下省略)
今度は都市名が表示されるようになりました。このように、
WINDOW関数の構文
ここからは実際にWINSOW関数の利用方法を確認します。
WINDOW関数を利用するにはOVER句を使用します。OVER句のカッコの中にはPARTITION BY、
たとえば先ほどのクエリの場合、SELECT * FROM city order by CountryCode asc
で表示させた結果を、

cityテーブルを利用して、
mysql> SELECT id, CountryCode, District, Population, sum(Population) OVER(PARTITION BY CountryCode), sum(Population) OVER() FROM city ORDER BY CountryCode; +-----+-------------+----------+------------+-------------------------------------------------+------------------------+ | id | CountryCode | District | Population | sum(Population) OVER(PARTITION BY CountryCode) | sum(Population) OVER() | +-----+-------------+----------+------------+-------------------------------------------------+------------------------+ | 129 | ABW | – | 29034 | 29034 | 1429559884 | | 2 | AFG | Qandahar | 237500 | 2332100 | 1429559884 | | 3 | AFG | Herat | 186800 | 2332100 | 1429559884 | | 1 | AFG | Kabol | 1780000 | 2332100 | 1429559884 | | 4 | AFG | Balkh | 127800 | 2332100 | 1429559884 | | 56 | AGO | Luanda | 2022000 | 2561600 | 1429559884 | | 59 | AGO | Benguela | 128300 | 2561600 | 1429559884 | | 57 | AGO | Huambo | 163100 | 2561600 | 1429559884 | | 60 | AGO | Namibe | 118200 | 2561600 | 1429559884 | | 58 | AGO | Benguela | 130000 | 2561600 | 1429559884 | (以下省略)
sum(Population) OVER(PARTITION BY CountryCode)
には各国のPopulationの合計値が入ってきました。また、sum(Population) OVER()
には全体のPopulationの合計値が出力されています。
下記の結果より、
> SELECT sum(Population) FROM city; +-----------------+ | sum(Population) | +-----------------+ | 1429559884 | +-----------------+ 1 row in set (0.00 sec)
WINDOW関数で利用できる集約関数と非集約関数
WINDOW関数で利用できる集約関数はCOUNT()やMAX()など、
また、
関数名 | 概要 |
---|---|
CUME_ | 累積分布を計算します。 |
DENSE_ | パーティション内のランクを返します。RANKと違って連続する数字でランクを割り当てます。 |
FIRST_ | パーティション内の最初の行を返します。 |
LAG() | パーティション内でN行前の値を返します。 |
LAST_ | パーティション内の最後の行を返します |
LEAD() | パーティション内でN行先の値を返します。 |
NTH_ | ウィンドウフレーム内のN行目を返します。 |
NTILE() | 全体をN分割したときにどこに属するかを返します。 |
PERCENT_ | パーティション内の%ランクを返します。 |
RANK() | パーティション内のランクを返します。 |
ROW_ | パーティション内で順番をつけます。 |
例として、
RANK関数を利用して、
mysql>SELECT -> id, -> CountryCode, -> District, -> Population, -> sum(Population) OVER(PARTITION BY CountryCode) as sum_population, -> rank() OVER(PARTITION BY CountryCode ORDER BY Population desc ) as district_ranking, -> row_number() OVER() as row_num -> FROM city ORDER BY CountryCode, district_ranking; +------+-------------+------------------------+------------+----------------+------------------+---------+ | id | CountryCode | District | Population | sum_population | district_ranking | row_num | +------+-------------+------------------------+------------+----------------+------------------+---------+ | 129 | ABW | – | 29034 | 29034 | 1 | 1 | | 1 | AFG | Kabol | 1780000 | 2332100 | 1 | 2 | | 2 | AFG | Qandahar | 237500 | 2332100 | 2 | 3 | | 3 | AFG | Herat | 186800 | 2332100 | 3 | 4 | | 4 | AFG | Balkh | 127800 | 2332100 | 4 | 5 | | 56 | AGO | Luanda | 2022000 | 2561600 | 1 | 6 | | 57 | AGO | Huambo | 163100 | 2561600 | 2 | 7 | | 58 | AGO | Benguela | 130000 | 2561600 | 3 | 8 | | 59 | AGO | Benguela | 128300 | 2561600 | 4 | 9 | | 60 | AGO | Namibe | 118200 | 2561600 | 5 | 10 | ~ ~ | 4070 | ZWE | Harare | 274912 | 2730420 | 3 | 4076 | | 4071 | ZWE | Harare | 164362 | 2730420 | 4 | 4077 | | 4072 | ZWE | Manicaland | 131367 | 2730420 | 5 | 4078 | | 4073 | ZWE | Midlands | 128037 | 2730420 | 6 | 4079 | +------+-------------+------------------------+------------+----------------+------------------+---------+ 4079 rows in set (0.02 sec)
RANK関数を利用してDistrictごとでPopulationのランキングを付けることができました。row_
今までは相関サブクエリや一時集計テーブルを駆使して出力していたものが簡単に出力することができました。
それぞれの詳細な使い方については、
フレームについて
フレームは分割された各パーティションでどこまでを対象とするかを定めることができます。たとえば、ROWS UNBOUNDED PRECEDING
とすればパーティションの開始行から現在までのすべての行をフレームとして定義でき、ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
とすれば、
名前付きWINDOW
WINDOWは名前をつけることができ、
> SELECT -> CountryCode, -> sum(Population) OVER w as sum_population, -> avg(Population) OVER w as avg_population -> FROM city WINDOW w AS (PARTITION BY CountryCode) -> ORDER BY CountryCode limit 20; +-------------+----------------+----------------+ | CountryCode | sum_population | avg_population | +-------------+----------------+----------------+ | ABW | 29034 | 29034.0000 | | AFG | 2332100 | 583025.0000 | | AFG | 2332100 | 583025.0000 | | AFG | 2332100 | 583025.0000 | | AFG | 2332100 | 583025.0000 | | AGO | 2561600 | 512320.0000 | | AGO | 2561600 | 512320.0000 | | AGO | 2561600 | 512320.0000 | | AGO | 2561600 | 512320.0000 | (以下省略)
まとめ
今回は、