こんにちは、株式会社KIYONOのエンジニアです。
今回は、分析する際などに非常に便利なwindow関数について、window関数とは何か?構文、どのようなシーンで活用できるのかなどをご紹介させて頂きたいと思います。
window関数って何?って方、構文ぐらいならわかるけど、どんな場面で使えばいいのかわからないって方にご覧いただければと思います。
window関数とは?
——————————————————————————
MySQLリファレンス
ウィンドウ関数は、一連のクエリー行に対して集計のような操作を実行します。 ただし、集計操作ではクエリー が単一の結果行にグループ化されますが、ウィンドウ関数ではクエリー行ごとに結果が生成されます
BigQueryドキュメント
分析関数(ウィンドウ関数ともいいます)は、行のグループに対して値を計算し、各行に対して 1 つの結果を返します。これは、行のグループに対して 1 つの結果を返す集計関数とは異なります。
分析関数には、評価対象の行を囲む行のウィンドウを定義する OVER 句が含まれています。各行について、選択された行のウィンドウを入力として使用して分析関数の結果が計算され、場合によっては集計が行われます。
分析関数を使用すると、移動平均の計算、項目のランク付け、累積合計の計算、その他の分析を行うことができます。
完結に説明すると、ウィンドウ関数は、結果行の集約を行わずに集計・分析のための計算を行うことのできる関数。
———————————————————————————————————————————–
ウィンドウ関数と集計関数の違い
- ウィンドウ関数には、AVG・SUM・MAX・MINなどの集計関数と同じ関数がある。
- 集計関数との違いは、出力結果が異なる。
- 集計関数は、グループごとの、レコードの集約を行なった1行の結果を返す。
- ウィンドウ関数では、レコードの集約は行わず、入力と同じ数のレコードを返す。
集計関数の処理結果のイメージ
store_id | item | price |
---|---|---|
1 | bread | 180 |
1 | pudding | 160 |
1 | cake | 380 |
出力データ
store_id | price_sum |
---|---|
1 | 720 |
・集約関数は、1レコードに集約される。
ウィンドウ関数の処理結果のイメージ
store_id | item | price |
---|---|---|
1 | bread | 180 |
1 | pudding | 160 |
1 | cake | 380 |
出力データ
store_id | item | price | price_sum |
---|---|---|---|
1 | bread | 180 | 180 |
1 | pudding | 160 | 340 |
1 | cake | 380 | 720 |
•ウィンドウ関数は、対象のレコードはそのまま残る。
window関数構文
window関数 OVER句([PARTITION BY句][OREDER BY句][フレーム句])無名ウィンドウ構文
無名ウィンドウ構文
SELECT store_id,
item,
price,
AVG(price) OVER(ORDER BY store_id ROWS BETWEEN 2
PRECEDING AND CURRENT ROW) AS price_avg
FROM Company;
SELECT
store_id,
item,
price,
AVG(price) OVER W AS price_avg
FROM Company
WINDOW W AS(ORDER BY shohin_id ROWS BETWEEN 2 PRECEDING
AND CURRENT ROW) ;
OVRE句
ウィンドウ関数を使いますよという、宣言になります。OVER句の後ろに、ウィンドウ関数を作る形になります。
PARTITION BY句
PARTITION BY句で指定したカラムをもとに、レコードを分割する。
ORDER BY句
OREDER BY句で指定した絡むを基準に、レコードをソートする。
フレーム句
カレントレコードを基準とした、処理範囲の調節をする。
・ROWS: 移動単位をレコードで設定する。
・RANGE: 移動単位をカラムで設定する。
・n PRECEDING: nだけ前へ移動する。
・n FOLLOWING: nだけ後ろへ移動する。
window関数のユースケース
————————————————————————————-
SUM
月ごとの累計会員数を合計として出力。
SELECT created_at,
register,
SUM(register) OVER (ORDER BY created_at) as moving_sum
FROM bakery;
created_at | register | moving_sum |
---|---|---|
2022-03-01 | 30 | 30 |
2022-04-01 | 60 | 90 |
2022-05-01 | 20 | 110 |
2022-06-01 | 30 | 140 |
・移動合計を見る時などに活用できます、累計会員数や累計売上、累計来店数など。
AVG
累計平均会員数を、平均として出力。
SELECT
created_at,
register,
AVG(register) OVER (ORDER BY created_at) as moving_avg,
SUM(register) OVER (ORDER BY created_at) as moving_sum
FROM bakery;
created_at | register | moving_avg | moving_sum |
---|---|---|---|
2022-03-01 | 30 | 30 | 30 |
2022-04-01 | 60 | 45 | 90 |
2022-05-01 | 20 | 36.7 | 110 |
2022-06-01 | 30 | 35 | 140 |
・株価や気温など移動平均を用いる際に活用できる。
COUNT
レコード数をカウントする。
SELECT implementation_date,
subject,
user_id,
score,
COUNT(user_id) OVER (PARTITION BY user_id) as total_tests
FROM scores
ORDER BY implementation_date, subject, user_id;
LAG/LEAD
指定レコード分、前の値・後ろの値を付与する。
月ごとの売り上げデータの、前月、後月との差分を出力。
SELECT created_at,
sales,
sales - LAG(sales, 1, 0) OVER (ORDER BY created_at) AS diff
FROM bakery;
created_at | sales | diff |
---|---|---|
2022-03-01 | 1000 | null |
2022-04-01 | 900 | -100 |
2022-05-01 | 850 | -50 |
2022-06-01 | 900 | 50 |
・売上データの、前日・後日、前月・来月などを見比べる時。
・変更履歴の変更前、変更後を確認するとき。
RANK
順位付けを行う。
売り上げが高い順にランキングをつける。
SELECT store_id,
sales,
RANK() OVER (PARTITION BY store_id ORDER BY sales DESC) as ranking
FROM bakery;
store_id | sales | ranking |
---|---|---|
3 | 1000 | 1 |
8 | 900 | 2 |
1 | 850 | 3 |
4 | 700 | 4 |
・順位付け等行う際に活用できる。
NTILE
指定したグループ数で分類してランク付けを行う。分類は近い値でグルーピングされる。
SELECT store_id,
sales,
NTILE(3) OVER (ORDER BY sales desc) as g_rank
FROM bakery;
store_id | sales | g_rank |
---|---|---|
2 | 1000 | 1 |
8 | 950 | 1 |
1 | 750 | 2 |
4 | 450 | 3 |
3 | 400 | 3 |
DENSE_RANK
グループのランクを振る。
同率順位があっても順位が繰り下がらないところが rank() との違い。
SELECT store_id,
sales,
DENSE_RANK() OVER (PARTITION BY store_id ORDER BY sales desc) AS d_rnk,
RANK() OVER (PARTITION BY store_id ORDER BY sales desc) as rnk
FROM bakery;
store_id | sales | d_rnk | rnk |
---|---|---|---|
2 | 1000 | 1 | 1 |
8 | 950 | 2 | 2 |
1 | 750 | 2 | 2 |
4 | 450 | 3 | 4 |
3 | 400 | 4 | 5 |
PERCENT_RANK
パーセントランクを算出する。
ランク最上位を 0 としてランクをパーセントで振る。
ランクの範囲は 0 〜 1
パーセントランクの計算式は(rank – 1)/(ウィンドウまたはパーティションの行数 – 1)
SELECT store_id,
sales,
RANK() OVER (PARTITION BY store_id ORDER BY sales desc) as rnk,
PERCENT_RANK() OVER (PARTITION BY store_id ORDER BY sales desc) as p_rnk
FROM bakery;
store_id | sales | rnk | p_rnk |
---|---|---|---|
2 | 1000 | 1 | 0 |
8 | 950 | 2 | 0.25 |
1 | 750 | 3 | 0.5 |
4 | 450 | 4 | 0.75 |
3 | 400 | 5 | 1 |
FIRST_VALUE / LAST_VALUE / NTH_VALUE
グループにおいてそれぞれ最初・最後・指定行の値を振る。
SELECT store_id,
SUM(sales),
FIRST_VALUE(sales) OVER (PARTITION BY store_id ORDER BY sales) as first,
LAST_VALUE(sales) OVER (PARTITION BY store_id ORDER BY sales ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as last,
NTH_VALUE(sales ,3) OVER (PARTITION BY store_id ORDER BY sales DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as third_value
FROM bakery;
store_id | sales | first | last | third_value |
---|---|---|---|---|
2 | 10000 | 1000 | 3000 | 2000 |
8 | 9500 | 700 | 2500 | 1500 |
1 | 7500 | 600 | 2000 | 1200 |
4 | 4500 | 400 | 1500 | 1000 |
3 | 4000 | 200 | 1000 | 500 |
・ユーザーの初回購入と最終購入などで活用できる。
まとめ
いかがだったでしょうか?このようにウィンドウ関数を使うことで分析する際に便利な関数が揃っています。
今回紹介した関数以外にも、様々な便利で活用的な関数が揃っているので是非興味がある方は調べて実際に活用してみてはいかがでしょうか!!
コメント