【うぃんどうかんすう】

ウィンドウ関数 とは?

💡 行をまとめずに「周辺の行を見ながら計算する」SQL関数
📌 このページのポイント
SUM(売上) OVER(PARTITION BY 部門 ORDER BY 月) 元テーブル 部門 売上 営業 1月 100 営業 2月 150 営業 3月 200 パーティション1 開発 1月 80 開発 2月 120 開発 3月 90 パーティション2 計算 ウィンドウ関数の結果 部門 売上 累計 順位 営業 1月 100 100 3 営業 2月 150 250 2 営業 3月 200 450 1 開発 1月 80 80 3 開発 2月 120 200 1 開発 3月 90 290 2 累計 = SUM(売上) OVER( PARTITION BY 部門 ORDER BY 月) 順位 = RANK() OVER( PARTITION BY 部門 ORDER BY 売上 DESC)
ウィンドウ関数の仕組み
ひよこ ひよこ

ウィンドウ関数ってGROUP BYとどう違うの?

ペンギン先生 ペンギン先生

GROUP BYは行をまとめて1行にしてしまうけど、ウィンドウ関数は元の行を残したまま計算結果を各行に追加できる。例えば「売上一覧に、部署ごとの合計も一緒に表示する」場合、GROUP BYだと売上明細が消えるけど、ウィンドウ関数なら明細を残したまま部署合計を表示できる。

ひよこ ひよこ

具体的にどう書くの?

ペンギン先生 ペンギン先生

「SELECT name, salary, RANK() OVER (ORDER BY salary DESC) as rank FROM employees」で全社員の給与ランキングが出る。「SUM(sales) OVER (PARTITION BY dept ORDER BY month)」なら部署ごとの月別累積売上が計算できる。OVER句が「ウィンドウ(計算範囲)」を定義するよ。

ひよこ ひよこ

ROW_NUMBERとRANKとDENSE_RANKの違いは?

ペンギン先生 ペンギン先生

同じ値が2つあるときの挙動が違う。ROW_NUMBERは必ず連番(1,2,3)で同値でも順番が付く。RANKは同値を同順位にして次の順位を飛ばす(1,1,3)。DENSE_RANKは同値を同順位にするけど次の順位を飛ばさない(1,1,2)。

ひよこ ひよこ

ウィンドウ関数ってパフォーマンスは大丈夫?

ペンギン先生 ペンギン先生

ウィンドウ関数はソートが必要だから、大量データだと負荷が高い。特にPARTITION BYとORDER BYが複雑になると、内部でソートが多重に走ることがある。さらに厄介なのはフレーム指定(ROWS BETWEEN〜)で、「ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW」と「RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW」は似ているようで重複値の扱いが全然違う。ROWSは物理的な行数で範囲を決め、RANGEは値の範囲で決める。ここの理解が曖昧だと集計結果がずれるのに、エラーにはならないから気づきにくいんだよね。

ペンギン
まとめ:ざっくりこれだけ覚えればOK!
ウィンドウ関数って出てきたら「GROUP BYで行をまとめずに、各行で周辺の行を参照しながら計算できる仕組み」と思えばだいたいOK!
📖 おまけ:英語の意味
「Window Function」 = 窓(Window)関数(Function)
💬 各行から見える範囲(窓=ウィンドウ)を定義して、その範囲で計算するイメージ
← 用語集にもどる