0Pricing
SQL Interview Prep · レッスン

ROWSとRANGEのフレーム指定

行ベースと値ベースのフレームの、微妙で頻出する違いを学びます。

「ROWSとRANGEのフレーム指定」はCoddyKit上の無料SQL Interview Prepレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはSQL Interview Prep学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 SQL Interview Prepコースには全4レッスンが含まれています。

面接官が確認する違い

累積合計を書けるようになると、自然な追加質問として次の内容が出てきます。「ウィンドウフレームにおける ROWS と RANGE の違いは何ですか。」 これは中級レベルの理解度を測る、明確な指標です。多くの受験者はフレームを日常的に使っていますが、この2つのキーワードの動作が異なることには気付いていません。

どちらも集約関数が参照する行の集合を定義しますが、その集合の数え方は根本的に異なります。ここを正しく理解できれば、周囲から一歩抜け出せます。

ROWS は物理的な行を数える

ROWS は位置に基づきます。ROWS BETWEEN 2 PRECEDING AND CURRENT ROW は、順序付けられた並びの中で、現在の行とその直前にある2つの物理的な行を文字どおり意味します。

隣接する行が同じ ORDER BY 値を持っているかどうかは関係ありません。3行なら、必ず3行です。これは、移動平均や厳密な累積合計でほぼ常に使いたいフレームです。

SELECT
  sale_date,
  amount,
  SUM(amount) OVER (
    ORDER BY sale_date
    ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
  ) AS rows_sum
FROM sales;

RANGE は値で数える

RANGE は値に基づきます。行数を数えるのではなく、現在の行の値に対する論理的な範囲内に ORDER BY の値が収まるすべての行を含めます。

最も重要な点は、RANGE では ORDER BY の値が同じすべての行が、1つのピアグループとして扱われることです。これらの行はすべて同じフレームになり、その結果も同じになります。

SELECT
  sale_date,
  amount,
  SUM(amount) OVER (
    ORDER BY sale_date
    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
  ) AS range_sum
FROM sales;

違いが明らかになる同順位の例

2024-03-01 に金額100の売上があり、その翌日の 2024-03-02 に金額30と40の売上が2件あったとします。

  • RANGE で CURRENT ROW までを指定した場合:03-02 の2行はピアなので、どちらも 100 + 30 + 40 = 170 になります。
  • ROWS で CURRENT ROW までを指定した場合:最初の 03-02 の行は130、2つ目の行は170になります。各行がフレームを1つずつ位置単位で広げるためです。

同じデータでも、結果は異なります。この同順位の場合の差こそが、この質問の核心です。

デフォルトが RANGE である理由

OVER (ORDER BY ...) に明示的なフレームを指定しない場合、デフォルトで RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW になることを思い出してください。

つまり、単純な累積合計では暗黙に RANGE が使われます。並び順のキーが一意なら ROWS と同じなので、問題が隠れます。しかし、並び順の値が重複した瞬間に、累積合計は同じ値の行をひそかにひとまとめにします。経験豊富なエンジニアが ROWS を明示的に書くのはこのためです。

数値オフセット付きのRANGE

RANGE は UNBOUNDED だけでなく、値のオフセットも受け取れます。日付列または数値列に対して RANGE BETWEEN 7 PRECEDING AND CURRENT ROW を使うと、現在の値から7単位以内にあるすべての行が含まれます。

日付に対して使うと、欠落した日を正しく飛ばす真の「直近7日間」ウィンドウになります。一方、ROWS 7 PRECEDING は間隔に関係なく直前の7行を取得します。この違いを理解していることは、面接で有力な回答になります。

SELECT
  sale_date,
  amount,
  SUM(amount) OVER (
    ORDER BY sale_date
    RANGE BETWEEN INTERVAL '7 days' PRECEDING AND CURRENT ROW
  ) AS last_7_days
FROM sales;

ROWSはギャップを無視する

逆に、ROWS にはデータの間隔という概念がありません。売上テーブルに週末のデータがない場合、ROWS BETWEEN 6 PRECEDING AND CURRENT ROW は7記録済み日分を対象にするため、実際には2暦週間にまたがる可能性があります。

したがって、選択は目的によって決まります。直近N件のレコードを意味するなら ROWS、値の直近N単位(日数や金額)を意味するならオフセット付きの RANGE を使います。

SQL方言の対応状況を確認

率直な面接回答では、対応状況の違いにも触れます。

  • PostgreSQL は、オフセット付きの RANGE(v11以降)と ROWS を完全にサポートしています。
  • SQL Server は ROWS と RANGE をサポートしていますが、RANGE で使えるのは UNBOUNDED/CURRENT ROW のみで、数値オフセットには対応していません。
  • MySQL 8 は両方をサポートしていますが、RANGE のオフセットの型には制限があります。

数値の RANGE オフセットが使えない場合は、自己結合または生成したカレンダーを使って同等の処理を実現します。これに触れると、本番環境を意識していることを示せます。

GROUPS:3つ目のモード

あまり知られていない3つ目のフレームモードとして GROUPS があります。これは行や値ではなく、同順位グループを数えます。GROUPS BETWEEN 1 PRECEDING AND CURRENT ROW では、現在の同順位グループと、その1つ前のグループが含まれます。

実際に必要になることはほとんどありませんが、「ほかにフレームモードはありますか」と聞かれたときに名前を挙げられると、深い理解を示せます。PostgreSQL 11以降など、いくつかのデータベースがサポートしています。

SELECT
  sale_date,
  amount,
  SUM(amount) OVER (
    ORDER BY sale_date
    GROUPS BETWEEN 1 PRECEDING AND CURRENT ROW
  ) AS two_day_groups
FROM sales;

暗唱できる判断基準

このテーマ全体を、面接で言える1文にまとめます。

「固定数の物理行を意味する場合はROWS、順序付け値の論理的な範囲を意味する場合はRANGEを使います。また、デフォルトのRANGEは同じ値をまとめるため、同値があると両者の結果が異なることを覚えておきます。」

この1文だけで、質問に完全かつ自信を持って答えられます。

左右で比較

1つのクエリに両方のフレーム指定を入れると、違いが分かりやすくなります。日付が重複するデータに対して実行し、2つの列を行ごとに比較してください。

日付が一意なら列の値は完全に一致します。同じ日付がある場合は、RANGE 列では同順位の行に同じ合計が繰り返される一方、ROWS 列では1行ずつ増加します。

SELECT
  sale_date,
  amount,
  SUM(amount) OVER (ORDER BY sale_date
    ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS rows_total,
  SUM(amount) OVER (ORDER BY sale_date
    RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS range_total
FROM sales;

クイックチェック

デフォルトのフレームで、ORDER BYの値が同じ2行があります。どうなりますか。

まとめ:ROWSとRANGE

ROWS は物理的な行数を数えます。RANGE は順序付け列の論理的な値に基づいて数え、同じ値を同順位の行としてまとめます。デフォルトの OVER (ORDER BY ...) フレームは RANGE です。そのため、単純な累積合計では同じソート値を持つ行がひとまとめになることがあります。

「直近N件のレコード」やデータの欠落に左右されない移動ウィンドウには ROWS を選びます。「直近N日間・Nドル」のように間隔を考慮する場合は、オフセット付きの RANGE を選びます。GROUPS の存在を知っていれば、さらに評価されます。次は ROWS のフレーム指定を使って移動平均を作成します。

よくある質問

「ROWSとRANGEのフレーム指定」レッスンは無料ですか?

はい。「ROWSとRANGEのフレーム指定」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、SQL Interview Prepコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 SQL Interview Prepコースには全4レッスンが含まれています。

「ROWSとRANGEのフレーム指定」で何を学びますか?

行ベースと値ベースのフレームの、微妙で頻出する違いを学びます。 ブラウザで直接実行するハンズオンコードでSQL Interview Prepを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

SQL Interview Prepを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのSQL Interview Prepは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「ROWSとRANGEのフレーム指定」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このSQL Interview Prepレッスンでコードを書いて実行できますか?

はい。すべてのSQL Interview Prepレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. ウィンドウフレームで累積合計を求める
  2. ROWSとRANGEのフレーム指定
  3. スライディングウィンドウで移動平均を求める
  4. 累積分布と全体に占める割合
← SQL Interview Prepに戻る