SQL Interview Prep · レッスン

上位N件で同順位を扱う

同順位の行をすべて含めるためにRANKとDENSE_RANKを使い分ける方法を学びます。

レッスン 2/413 ステップ

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

同率の場合に関する追加質問

ROW_NUMBERでTop-Nの問題を解けるようになると、面接官はさらに掘り下げてきます。「境界で2人の従業員の給与が完全に同じだった場合、2人とも含めるべきですか?」

この質問では、1つのクエリを暗記しただけの候補者と、順位付けの意味を理解している候補者を見分けます。答えはROW_NUMBER、RANK、DENSE_RANKのどれを選ぶかによって決まります。このレッスンでは、各関数をどのようなビジネス上の意図に対応させるかを整理します。

ROW_NUMBERでは同率を区別できない

ROW_NUMBERは、各行に厳密に一意の整数を割り当てます。並べ替えの列が同じ行同士でも、任意の順序で一方が2、もう一方が3になります。

その結果、WHERE rn <= 3というフィルターは必ず3行を返しますが、本来なら含めるべき同率の行を気付かないまま除外する可能性があります。件数を厳密に固定したい場合には問題ありませんが、同率の行をすべて対象にすべき場合には不適切です。

-- Salaries: 100, 90, 90, 80
-- ROW_NUMBER -> 1, 2, 3, 4  (the two 90s get 2 and 3 arbitrarily)
ROW_NUMBER() OVER (ORDER BY salary DESC)

RANKでは順位に欠番が生じる

RANKは同率の行に同じ順位を与え、その後の順位を同率の数に応じて飛ばします。2位が2行ある場合、両方が2位となり、次の行は3位ではなく4位になります。

「上位3つの順位」のように、1つの順位を複数人が占める可能性がある場合はRANKを使います。これは、2人の銀メダリストがいる場合に銅メダリストが存在しない、実際の競技の順位表に似た考え方です。

-- Salaries: 100, 90, 90, 80
-- RANK -> 1, 2, 2, 4   (rank 3 is skipped)
RANK() OVER (ORDER BY salary DESC)

DENSE_RANKでは欠番が生じない

DENSE_RANKも同率の行に同じ順位を与えますが、その後の順位を飛ばしません。2位が2行ある場合、両方が2位となり、次の異なる値は3位になります。

「給与水準の上位3つ」や「価格帯の上位3段階」のように、異なる値が対象となる場合はDENSE_RANKを使います。行数ではなく、一意な値の数を数える関数です。

-- Salaries: 100, 90, 90, 80
-- DENSE_RANK -> 1, 2, 2, 3   (no gap)
DENSE_RANK() OVER (ORDER BY salary DESC)

並べて比較する

給与の一覧が100、90、90、80の場合、3つの関数の結果は次のようになります。

  • ROW_NUMBER:1、2、3、4
  • RANK:1、2、2、4
  • DENSE_RANK:1、2、2、3

この表はそのまま覚えておく価値があります。面接官から与えられた一覧について表を埋めるよう求められることもあり、欠番の扱いを正しく答えることが重要です。

SELECT salary,
  ROW_NUMBER() OVER (ORDER BY salary DESC) AS rn,
  RANK()       OVER (ORDER BY salary DESC) AS rnk,
  DENSE_RANK() OVER (ORDER BY salary DESC) AS drnk
FROM employees;

RANKですべての同率行を含める

「上位3件。ただし境界で同率の行はすべて含める」という要件には、RANK() <= 3で答えます。2人が3位で同率の場合、両方が表示されるため、結果には3行を超える行が含まれる可能性があります。

これは、「任意の3行」ではなく「上位3つの順位」と表現された質問の意図です。同率がある場合は行数がNを超える可能性があることを、明確に説明してください。

WITH ranked AS (
  SELECT name, department, salary,
         RANK() OVER (
           PARTITION BY department ORDER BY salary DESC
         ) AS rnk
  FROM employees
)
SELECT name, department, salary, rnk
FROM ranked
WHERE rnk <= 3
ORDER BY department, rnk;

DENSE_RANKによる上位3つの異なる水準

「給与水準の上位3つ」を求め、これら3つの水準に該当するすべての従業員を含めたい場合は、DENSE_RANK() <= 3を使います。

この場合、多くの行が返される可能性があります。上位3つの給与水準に含まれる従業員を、その水準に何人いてもすべて返すためです。重要なのは、DENSE_RANKが異なる値を数えるため、このフィルターは固定した行数ではなく、値の層を選択するという点です。

WITH ranked AS (
  SELECT name, salary,
         DENSE_RANK() OVER (ORDER BY salary DESC) AS drnk
  FROM employees
)
SELECT name, salary, drnk
FROM ranked
WHERE drnk <= 3
ORDER BY drnk;

使い分けの指針

質問の表現を関数に対応付けます。

  • 「正確にN行」またはページネーション → ROW_NUMBER(タイブレーカーを追加します)。
  • 「上位N個の順位。同率は同じ順位」 → RANK。
  • 「異なる値・水準・段階の上位N個」 → DENSE_RANK。

仕様が曖昧な場合は、「境界で同率があるとき、同率の行をすべて含めますか、それともN件で制限しますか?」と確認してください。この確認自体が評価されます。

タイブレーカーは依然として重要

RANKやDENSE_RANKを使う場合でも、第2のORDER BYキーを追加すると、同率の行の表示順を制御でき、出力を安定させられます。どの行が対象になるかは変わりませんが、結果を再現可能にできます。

ROW_NUMBERでは、タイブレーカーが不可欠です。rnのカットオフを超えて残る同率の行を決めるためです。

RANK() OVER (
  PARTITION BY department
  ORDER BY salary DESC, name ASC
) AS rnk

例題:得点上位者

game_scoresテーブルにplayerとscoreがあります。面接官は「得点順位の上位2位までに入るすべてのプレイヤー」を求めています。1位が同率なら、2人が1位となり、次に異なる得点が2位になります。

同率の後に順位を飛ばさない「順位」という表現は、DENSE_RANKを示しています。もし「順位を飛ばす上位2つの順位」と言われた場合は、RANKに切り替えます。正確な表現を聞き取りましょう。

WITH r AS (
  SELECT player, score,
         DENSE_RANK() OVER (ORDER BY score DESC) AS pos
  FROM game_scores
)
SELECT player, score, pos
FROM r
WHERE pos <= 2
ORDER BY pos, player;

避けるべきよくある間違い

面接官が注目する落とし穴は次のとおりです。

  • 同率を含める必要がある質問でROW_NUMBERを使い、該当する行を気付かないまま除外する。
  • RANKとDENSE_RANKの欠番の扱いを混同する。
  • RANKやDENSE_RANKのフィルターがN行を超える結果を返すことを忘れ、結果が間違っていると判断する。
  • グループごとのTop-NなのにPARTITION BYを省略し、テーブル全体に対して順位を付ける。

クイックチェック

説明されている同順位の扱いに適したランキング関数を選択してください。

まとめ:同順位の扱い

3つの関数、3通りの同順位の扱いがあります。

  • ROW_NUMBER:常に一意で、ちょうどN行を返し、同順位は任意の順序で解消されます。
  • RANK:同順位は同じ順位になり、その後に欠番が生じます。
  • DENSE_RANK:同順位は同じ順位になり、欠番は生じず、異なる値の数を基準にします。

設問の文言に応じて選び、曖昧な場合は確認の質問をし、RANK/DENSE_RANKによるフィルタでは、仕様上N行を超える行が返る場合があることを覚えておいてください。

無料で開始

AI チューターと学ぶ SQL — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
30
レッスン
120

よくある質問

「上位N件で同順位を扱う」レッスンは無料ですか?

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

「上位N件で同順位を扱う」で何を学びますか?

同順位の行をすべて含めるためにRANKとDENSE_RANKを使い分ける方法を学びます。 ブラウザで直接実行するハンズオンコードでSQL Interview Prepを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

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

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

「上位N件で同順位を扱う」レッスンにはどのくらい時間がかかりますか?

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

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

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

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

  1. ROW_NUMBERでグループごとに上位N行を取得する
  2. 上位N件で同順位を扱う
  3. 安全に行の重複を除去する
  4. キーごとに最新の行を残す
← SQL Interview Prepに戻る