Xorthax can now pull values from specific positions. But what if he wants to label each row in order?
“Which row is first?” “Which row is second?”
That’s what ROW_NUMBER() does.
ROW_NUMBER() assigns a unique number to each row in a sequence.
ROW_NUMBER() OVER (
PARTITION BY column
ORDER BY column
)
This works because:
PARTITION BY defines the groupORDER BY defines the sequence| CustomerID | OrderDate | Amount |
|---|---|---|
| A | 2024-01-01 | 100 |
| A | 2024-01-05 | 150 |
| B | 2024-01-02 | 200 |
| B | 2024-01-06 | 50 |
SELECT CustomerID, OrderDate, Amount,
ROW_NUMBER() OVER (
PARTITION BY CustomerID
ORDER BY OrderDate
) AS RowNum
FROM Orders;
Result:
| CustomerID | OrderDate | Amount | RowNum |
|---|---|---|---|
| A | 2024-01-01 | 100 | 1 |
| A | 2024-01-05 | 150 | 2 |
| B | 2024-01-02 | 200 | 1 |
| B | 2024-01-06 | 50 | 2 |
Each row now has a position within its customer group.
PARTITION BY CustomerID creates a group for each customer.
ORDER BY OrderDate defines the sequence within each group.
ROW_NUMBER() assigns a number starting at 1 and increases by 1 for each row.
The numbering resets for each group.
⚠️ Important: If two rows have the same value in the ORDER BY column, the order between them is not guaranteed.
That means ROW_NUMBER() will still assign unique numbers, but the order of those tied rows may change each time the query runs.
To make results consistent, add additional columns to the ORDER BY.
For each order, assign a row number based on orderdate.
| Column | Type |
|---|---|
| orderid | bigint |
| customerid | bigint |
| orderdate | timestamp without time zone |
| totalamount | double precision |
| status | text |
| Column |
|---|
| orderid |
| orderdate |
| totalamount |
| order_number |
ROW_NUMBER() gives each row a unique position.
Next, you’ll learn how to rank rows when there are ties.