sqlcmd.net validated sql reference
advanced windowing MySQL MariaDB SQL Server PostgreSQL SQLite

Rank Rows With Gaps Using RANK And DENSE_RANK

Assign rank numbers to rows within a partition, controlling whether tied ranks leave gaps in the sequence.

Docker-validated Not currently validation-green

Rank players on a leaderboard showing the difference between RANK and DENSE_RANK

Alice and Carol both score 100 and share rank 1. With RANK, Bob's next position is 3 (rank 2 is skipped because two players tied for 1st). With DENSE_RANK, Bob's next position is 2 — no gap. Dave follows at rank 4 (RANK) or rank 3 (DENSE_RANK).

Rows loaded before the example query runs.
Setup
CREATE TABLE scores (id INT, player VARCHAR(50), score INT);

INSERT INTO
  scores (id, player, score)
VALUES
  (1, 'Alice', 100),
  (2, 'Bob', 85),
  (3, 'Carol', 100),
  (4, 'Dave', 70);
Shared across supported engines.
SQL
SELECT
  player,
  score,
  RANK() OVER (
    ORDER BY
      score DESC
  ) AS rank_num,
  DENSE_RANK() OVER (
    ORDER BY
      score DESC
  ) AS dense_rank_num
FROM
  scores
ORDER BY
  score DESC,
  player;
Returned rows for the shared example.
playerscorerank_numdense_rank_num
Alice10011
Carol10011
Bob8532
Dave7043

Output is identical across all supported engine versions.

Where this command helps.

  • building a leaderboard where tied scores share the same rank
  • distinguishing gap-preserving rank from continuous dense rank

What the command is doing.

RANK() assigns the same rank to tied rows but skips subsequent rank numbers — two rows tied at rank 1 are followed by rank 3, not rank 2. DENSE_RANK() also assigns the same rank to ties but never skips numbers — the next rank after a tie is always the next integer. Use RANK when gaps are meaningful (e.g. competition standings) and DENSE_RANK when a continuous sequence matters more.