第33回ブログ:今さらながら完全理解!SQL ウィンドウ関数まとめ

SQL Window Functions Banner

🔍 はじめに ― なぜ今ウィンドウ関数なのか?

2025 年、生成 AI は複雑なクエリも書けるようになりましたが、「どんなクエリが最適か」を判断できるのは依然として人間です。
とくに 集計+詳細 を同時に取得できるウィンドウ関数(分析関数)は、BI/DX の現場で避けて通れません。
本記事では PostgreSQL / MySQL 8 / BigQuery / Redshift で共通して使える構文と実務レシピを網羅します。

🗂 基本構文の整理

カテゴリ代表関数用途
順位づけROW_NUMBER()
RANK()
DENSE_RANK()
ランキング表・トップ N 抽出
移動集計LAG() / LEAD()
FIRST_VALUE()
LAST_VALUE()
前後比較・差分計算
累積集計SUM() OVER
AVG() OVER
売上累計・移動平均
分位点PERCENT_RANK()
NTILE(n)
パーセンタイル・箱ひげ図

💡 PARTITION と ORDER BY の鉄則

🧑‍💻 実務レシピ 10 連発

  1. 月次売上累計
    SELECT
      order_date,
      SUM(amount) OVER(ORDER BY order_date) AS running_total
    FROM sales;
  2. ユーザー別ランキング
    SELECT
      user_id,
      total_points,
      RANK() OVER(PARTITION BY region ORDER BY total_points DESC) AS rank_in_region
    FROM leaderboard;
  3. 前週比成長率
    SELECT
      week,
      revenue,
      revenue - LAG(revenue) OVER(ORDER BY week) AS diff_prev_week,
      ROUND(100.0 * (revenue / LAG(revenue) OVER(ORDER BY week) - 1), 1) AS pct_growth
    FROM weekly_revenue;
  4. 売上トップ 3 店舗 / 地域
    SELECT *
    FROM (
      SELECT
        store_id, region, monthly_sales,
        ROW_NUMBER() OVER(PARTITION BY region ORDER BY monthly_sales DESC) AS r
      FROM store_sales
    ) t
    WHERE r <= 3;
  5. 移動平均(7 日間)
    SELECT
      d,
      temp,
      AVG(temp) OVER(
        ORDER BY d
        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
      ) AS ma7
    FROM weather;
  6. 商品価格の最安値・最高値
    SELECT
      product_id,
      price,
      MIN(price) OVER(PARTITION BY product_id)  AS min_p,
      MAX(price) OVER(PARTITION BY product_id)  AS max_p
    FROM price_history;
  7. パーセンタイル帯に分桶
    SELECT
      user_id,
      spend,
      NTILE(4) OVER(ORDER BY spend DESC) AS quartile
    FROM user_spend;
  8. 直近 3 注文の平均金額
    SELECT
      order_id,
      amount,
      AVG(amount) OVER(
        ORDER BY order_date
        ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
      ) AS avg_last3
    FROM orders;
  9. カスタム週次ランキング(タイ 1,2,2 → 3)
    SELECT
      week,
      team,
      score,
      DENSE_RANK() OVER(PARTITION BY week ORDER BY score DESC) AS dense_rank
    FROM team_score;
  10. 任意フレームの累計 & 残高計算
    SELECT
      tx_id,
      tx_time,
      amount,
      SUM(amount) OVER(
        ORDER BY tx_time
        RANGE BETWEEN INTERVAL '30 days' PRECEDING AND CURRENT ROW
      ) AS balance_30d
    FROM transactions;

🚀 ウィンドウ関数 × AI でさらに効率化

生成 AI に日本語プロンプトでウィンドウ関数を作らせる例:

「ユーザーごとに入会日からの経過月と、月ごとの累計課金額を求める SQL を書いて」

Copilot / Cursor / Gemini Code Assist は、上記プロンプトに対し DATE_TRUNC()SUM() OVER … ORDER BY を組み合わせたクエリを提示。
RAG 構成なら、メタデータとして information_schema を渡すことでカラム名の誤認も抑えられます。

📝 失敗例と回避策

ORDER BY 抜け
ROW_NUMBER() なのに ORDER BY を忘れると結果は不定。必ず確認。
フレーム誤指定
ROWS BETWEEN UNBOUNDED PRECEDING と書かずデフォルトの「現在行のみ」になり累積しない事故が多発。
NULL の扱い
PostgreSQLNULLS LASTBigQuery は常に NULLS LAST。環境差異に注意。

🔮 まとめ ― ウィンドウ関数は “覚える” から “組み合わせる” へ

ウィンドウ関数は、

SQL を生成 AI に任せる前提でも、“何を PARTITION し、どう ORDER するか”を理解していれば、クエリ品質とパフォーマンスを自分でコントロールできます。
ぜひウィンドウ関数を“道具箱”に入れ、AI と組み合わせた最速データ分析を体験してください。

← ブログTOPへ戻る