ROW_NUMBER() assigns a unique sequential integer to each row within a query’s result set or a specified partition.
ROW_NUMBER() returns an ascending integer starting at 1 for every row in the result set. When used with PARTITION BY, the count restarts for each partition.
The window function’s general form is:
ROW_NUMBER() OVER ( [PARTITION BY expr_list] [ORDER BY sort_list] )
PARTITION BY groups rows before numbering, while ORDER BY defines numbering order.
SELECT
ROW_NUMBER() OVER (ORDER BY id) AS rn,
id, name, price
FROM Products;
This query labels every product sequentially by primary key.
SELECT
customer_id,
ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date) AS order_seq,
id AS order_id, order_date, total_amount
FROM Orders;
Each customer’s orders start at 1, ordered by date.
SELECT
oi.order_id,
oi.product_id,
oi.quantity,
ROW_NUMBER() OVER (PARTITION BY oi.order_id ORDER BY oi.id) AS item_seq
FROM OrderItems oi
HAVING item_seq = 1;
The HAVING clause filters to the first row per order.
Always add an ORDER BY inside OVER to guarantee deterministic numbering. Use indexed columns to keep the operation fast on large datasets.
Omitting ORDER BY yields an indeterminate sequence. Forgetting PARTITION BY when needed causes numbering to continue across groups.
Yes. You can wrap the window function in a CTE or subquery and apply WHERE or HAVING to the generated column, e.g., WHERE rn = 1.
Not technically, but using indexed columns in ORDER BY improves performance, especially on large tables.
ROW_NUMBER() assigns unique integers with no gaps. RANK() skips numbers when ties occur, leaving gaps in the sequence.