SQL RANK() Function: Ties and PARTITION BY

You're going to learn RANK once and then spend your whole career choosing between it and ROW_NUMBER and DENSE_RANK. That's the real skill. The syntax takes ten minutes. Deciding which one to reach for takes a few hundred reps, and nobody walks you through the decision until you've already bombed one interview on it.

RANK() Syntax

RANK is a window function. It requires an OVER clause with ORDER BY. PARTITION BY is optional. Without PARTITION BY, the entire result set is treated as one group.

11%
Use RANK/DENSE_RANK
15%
Use ROW_NUMBER
3
Ranking functions to learn
1
Rule about tie gaps

RANK() Syntax

RANK() OVER (
  [PARTITION BY partition_column]
  ORDER BY sort_column [ASC | DESC]
)

-- Basic RANK: global ranking by score
SELECT
  student_name,
  exam_score,
  RANK() OVER (ORDER BY exam_score DESC) AS score_rank
FROM exam_results;

-- RANK with PARTITION BY: ranking per department
SELECT
  department,
  employee_name,
  salary,
  RANK() OVER (
    PARTITION BY department
    ORDER BY salary DESC
  ) AS dept_salary_rank
FROM employees;

RANK() Syntax Parts

PARTITION BY (optional)

Divides the result set into groups. RANK restarts at 1 for each group. Without PARTITION BY, all rows belong to a single group. You can partition by one or more columns. PARTITION BY department creates one ranking per department. PARTITION BY department, fiscal_year creates one ranking per department-year combination.

ORDER BY (required)

Defines the ranking criteria. ORDER BY salary DESC ranks the highest salary as 1. ORDER BY created_at ASC ranks the oldest record as 1. You must include ORDER BY; without it, most engines throw an error. SQL Server allows omitting it but returns nondeterministic results, which is never what you want.

How RANK Handles Ties

If you remember nothing else from this page, remember that ties are the entire point of RANK. The formula is simple: next rank equals current rank plus number of tied rows.

NameScoreRANK()
Alice951
Bob902
Carol902
Dave854
Eve805

Tie Behavior with RANK()

SELECT
  student_name,
  score,
  RANK() OVER (ORDER BY score DESC) AS rnk
FROM exam_results;

-- Alice  95  1
-- Bob    90  2
-- Carol  90  2
-- Dave   85  4   <-- rank 3 is skipped
-- Eve    80  5

Key insight: Bob and Carol both score 90 and both get rank 2. Dave gets rank 4, not 3. Rank 3 does not exist because positions 2 and 3 were both consumed by the tie. This is the gap that interviewers ask about.

RANK with PARTITION BY

PARTITION BY creates independent ranking windows. Each partition starts its ranking at 1. Without PARTITION BY, rows only compete against rows globally.

DepartmentNameSalaryRANK()
EngineeringAlice$150,0001
EngineeringBob$140,0002
EngineeringCarol$140,0002
EngineeringDave$130,0004
MarketingEve$120,0001
MarketingFrank$115,0002
MarketingGrace$110,0003

RANK with PARTITION BY

SELECT
  department,
  employee_name,
  salary,
  RANK() OVER (
    PARTITION BY department
    ORDER BY salary DESC
  ) AS dept_rank
FROM employees;

-- Multiple PARTITION BY columns
SELECT
  department,
  fiscal_year,
  employee_name,
  sales_total,
  RANK() OVER (
    PARTITION BY department, fiscal_year
    ORDER BY sales_total DESC
  ) AS yearly_sales_rank
FROM annual_sales;

When to Use RANK()

RANK is the right choice when ties should share a position and the gap after ties communicates meaningful information.

Competition-Style Leaderboards

When two contestants tie for 2nd place, there should be no 3rd place. The next contestant gets 4th. This is exactly what RANK does. The gap communicates that positions were consumed by the tie. Sports leaderboards, sales contests, and any ranking where ties share a position use RANK.

Percentile and Threshold Analysis

RANK is useful when you want to know the exact position of a row relative to all others, including the effect of ties. If 10 people tie for 1st, the 11th person is rank 11, not rank 2. Use this when you need to answer questions like 'how many people scored higher than this row?'

Filtering with Awareness of Tie Counts

When you write WHERE rank <= 3, RANK might return more than 3 rows if ties exist at the boundary. This is a feature, not a bug. If two people tie for 3rd, both are included. This behavior is what interviewers test: they want to see that you understand the result set size is not guaranteed when using RANK with a filter.

RANK vs DENSE_RANK vs ROW_NUMBER

All three are ranking window functions. They only differ in how they handle ties. Picking the wrong one is a silent bug: the query runs, returns results, and the interviewer waits to see if you notice.

FunctionTies?Gaps?Best For
RANK()YesYesCompetition rankings, positional analysis
DENSE_RANK()YesNoNth distinct value, consecutive numbering
ROW_NUMBER()NoNoDeduplication, exactly one row per group

3 RANK Interview Questions

These questions test whether you understand RANK beyond the textbook definition. Each includes what the interviewer is actually evaluating and how to structure your answer.

Q1

Explain the difference between RANK() and DENSE_RANK(). Give an example where they return different results.

Draw a concrete example with tied values. Show both outputs side by side. With scores 95, 90, 90, 85: RANK gives 1, 2, 2, 4. DENSE_RANK gives 1, 2, 2, 3. The gap in RANK means WHERE rnk = 3 returns nothing. WHERE dr = 3 with DENSE_RANK returns 85. Use DENSE_RANK when you need to address specific rank positions by number.

Q2

Write a query to find the top 2 highest-paid employees per department, including ties.

Use RANK() OVER (PARTITION BY department ORDER BY salary DESC) in a CTE, then filter WHERE rnk <= 2. Mention that the result may contain more than 2 rows per department if ties exist, and that this is the intended behavior.

Q3

A dashboard query uses RANK() but the stakeholder complains about 'missing' rank numbers. What is happening and how do you fix it?

RANK intentionally skips numbers after ties. If the business needs consecutive numbers, use DENSE_RANK. If the business needs exactly one row per rank, use ROW_NUMBER. Clarify the requirement before changing the query.

RANK and NULL Values

-- Control NULL placement explicitly
SELECT
  employee_name,
  salary,
  RANK() OVER (
    ORDER BY salary DESC NULLS LAST
  ) AS salary_rank
FROM employees;

-- NULLs are ranked together at the bottom
-- All NULL salary rows share the same rank

Best practice: Always use NULLS LAST or NULLS FIRST explicitly when your ORDER BY column might contain NULLs. In engines that do not support this syntax (like older MySQL versions), use COALESCE to replace NULLs with a sentinel value.

SQL RANK Function FAQ

What does the RANK function do in SQL?+
The RANK function assigns a positional number to each row based on the ORDER BY clause within the OVER window. Rows with identical ORDER BY values receive the same rank. After a tie, the next rank skips ahead by the number of tied rows. Two rows tied at rank 2 means the next row gets rank 4, not 3. The gap indicates that two positions were consumed by the tie. RANK works in PostgreSQL, MySQL 8+, SQL Server, Snowflake, BigQuery, Databricks, and every modern SQL engine.
How does RANK handle ties?+
When two or more rows have identical values in the ORDER BY column, RANK assigns them all the same number. It then skips the subsequent numbers. If three rows tie at rank 5, the next row gets rank 8 (not 6). The formula is: next rank = current rank + number of tied rows. This behavior mirrors competition ranking: if three runners tie for 5th, there is no 6th or 7th place. The next finisher is 8th.
Can you use RANK without PARTITION BY?+
Yes. Without PARTITION BY, RANK operates over the entire result set as a single partition. Every row is ranked against every other row. PARTITION BY is optional and only needed when you want independent rankings per group. RANK() OVER (ORDER BY salary DESC) ranks all employees globally. RANK() OVER (PARTITION BY department ORDER BY salary DESC) restarts the ranking at 1 for each department.
02 / Why practice

A dozen reps and you'll stop second-guessing

  1. 01

    Active recall beats re-reading by 50%

    Cognitive-science meta-reviews (Dunlosky et al., 2013) rank practice testing as a top-tier study technique, while re-reading and highlighting rank near the bottom

  2. 02

    76% of hiring managers reject on the coding task, not the resume

    From HackerRank's 2024 Developer Skills Report. Candidates who look strong on paper still fail the live screen if they haven't done timed, executable practice

  3. 03

    Five problem shapes cover 80% of data engineer loops

    Dedup, sessionization, top-N-per-group, slowly-changing dimensions, partition tricks. Writing the shapes by hand turns the unfamiliar into pattern recognition

Related Guides