Learnitweb

ROW_NUMBER()

What is ROW_NUMBER()?

ROW_NUMBER() is an analytic function in Oracle SQL that assigns a unique sequential number to each row within a result set or partition, based on a specific order.

Unlike the ROWNUM pseudocolumn (which is assigned before sorting), ROW_NUMBER() is assigned after the ORDER BY clause, which makes it more reliable for pagination, ranking, and ordered row selection.

Syntax

ROW_NUMBER() OVER (ORDER BY column_name)

Optional Partitioning:

ROW_NUMBER() OVER (PARTITION BY column_name ORDER BY another_column)

Key Points

FeatureDetails
TypeAnalytic function
Starts from1 for each partition
Can reset per group?Yes, with PARTITION BY
Order matters?Yes, you must specify ORDER BY
Deterministic?Yes — unlike ROWNUM, it’s order-aware

Example 1: Assign Row Numbers to All Employees by Salary

SELECT 
  employee_id, 
  first_name, 
  salary,
  ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num
FROM employees;

Result:

employee_idfirst_namesalaryrow_num
102Sarah150001
101John120002
103Linda100003

ROW_NUMBER() assigns unique numbers after sorting by salary DESC.

Example 2: Top Paid Employee in Each Department

SELECT *
FROM (
  SELECT 
    department_id,
    employee_id,
    salary,
    ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rn
  FROM employees
)
WHERE rn = 1;

Explanation:

  • The PARTITION BY clause resets row number for each department.
  • The outer query filters to keep only the top-paid employee per department.

Pagination with ROW_NUMBER()

Example: Get records from 11 to 20

SELECT *
FROM (
  SELECT e.*, ROW_NUMBER() OVER (ORDER BY employee_id) AS rn
  FROM employees e
)
WHERE rn BETWEEN 11 AND 20;

This is a common pattern for paginated queries:

  • Inner query assigns row numbers based on the desired sort order.
  • Outer query filters based on range.

Compare: ROW_NUMBER() vs RANK() vs DENSE_RANK()

FunctionHandles Ties?Skips Numbers?Use Case
ROW_NUMBER()No — all rows get unique numbersYesPagination
RANK()YesYesRanking with gaps
DENSE_RANK()YesNoRanking without gaps

Example (Same Salary):

SELECT
  employee_id,
  salary,
  ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_number,
  RANK() OVER (ORDER BY salary DESC) AS rank,
  DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rank
FROM employees;

Real-World Use Cases

Use CaseHow ROW_NUMBER() Helps
PaginationGet rows between N and M efficiently
Top-N per groupSelect top 1 product/customer/order in each group
De-duplicationKeep only the first row based on sorting
RankingAssign sequential ranks with order control

Limitations

LimitationExplanation
Must use subquery to filter ROW_NUMBER()You can’t use it directly in WHERE
Needs ORDER BYRequired for row numbering to work
Not compatible with older Oracle versionsRequires Oracle 8i or newer

Summary

FeatureDescription
NameROW_NUMBER()
TypeAnalytic function
PurposeAssign sequential row number based on sort
Partitions supported?Yes
Order-aware?Yes
Use casesPagination, ranking, top-N, de-duplication
Better than ROWNUM?Yes — because it’s predictable and flexible

Bonus: Oracle 12c+ Pagination (with FETCH)

If you’re on Oracle 12c or later, you can also do pagination like this:

SELECT *
FROM employees
ORDER BY employee_id
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;

But ROW_NUMBER() remains useful when:

  • You need to rank within partitions.
  • You want fine control over row numbers.