SQL Server - Using ROW_NUMBER() OVER PARTITION function to SET a value
SQL Server: Using ROW_NUMBER() OVER PARTITION to Set Values

Learn how to effectively use the ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...)
function in SQL Server to assign sequential numbers within groups and conditionally update or set values based on these rankings.
The ROW_NUMBER()
window function is a powerful tool in SQL Server for assigning a unique, sequential integer to rows within a specified partition of a result set. When combined with the PARTITION BY
and ORDER BY
clauses, it allows for sophisticated data manipulation, such as identifying the first, last, or Nth record within a group, and then using that information to set or update other values. This article will guide you through understanding and implementing ROW_NUMBER()
to achieve precise data modifications.
Understanding ROW_NUMBER() OVER (PARTITION BY ...)
The ROW_NUMBER()
function assigns a unique number to each row within a partition, starting from 1 for the first row in each partition. The PARTITION BY
clause divides the result set into partitions, and ORDER BY
determines the logical order of rows within each partition. Without PARTITION BY
, ROW_NUMBER()
treats the entire result set as a single partition. This function is non-deterministic if the ORDER BY
clause does not guarantee a unique order for rows within a partition.
flowchart TD A[Start Query] --> B{Define Partition (PARTITION BY)}; B --> C{Order Rows within Partition (ORDER BY)}; C --> D[Assign ROW_NUMBER() to each row]; D --> E{Filter or Update based on ROW_NUMBER()};
Conceptual flow of ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...) operation.
Basic Syntax and Example
The basic syntax for ROW_NUMBER()
is straightforward. Let's consider a scenario where you have a table of orders, and you want to assign a sequential number to each order placed by a specific customer, ordered by the order date.
SELECT
OrderID,
CustomerID,
OrderDate,
ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY OrderDate) AS CustomerOrderRank
FROM
Orders;
Assigning a rank to orders per customer based on order date.
Setting a Value Based on ROW_NUMBER()
A common use case is to identify a specific row within a group (e.g., the first or most recent) and then update a value based on that identification. For instance, you might want to mark the first order for each customer as their 'Initial Order'. This requires using the ROW_NUMBER()
result in a subquery or Common Table Expression (CTE) to then perform an UPDATE
statement.
WITH RankedOrders AS (
SELECT
OrderID,
CustomerID,
OrderDate,
ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY OrderDate ASC) AS rn
FROM
Orders
)
UPDATE O
SET
IsInitialOrder = 1
FROM
Orders O
INNER JOIN
RankedOrders RO ON O.OrderID = RO.OrderID
WHERE
RO.rn = 1;
Updating a flag for the first order of each customer using ROW_NUMBER().
ORDER BY
clause within ROW_NUMBER()
is sufficiently unique to guarantee consistent results, especially when using it for updates. If two rows have the same OrderDate
for the same CustomerID
, their relative order might not be guaranteed without an additional tie-breaker column like OrderID
.Handling Duplicates and Specific Scenarios
What if you need to set a value for only one of several duplicate records, or perhaps for the second-most recent record? ROW_NUMBER()
is ideal for these scenarios. By adjusting the ORDER BY
clause or the WHERE
condition in your outer query, you can target specific rows.
-- Example: Mark the second most recent order for each customer
WITH RankedOrders AS (
SELECT
OrderID,
CustomerID,
OrderDate,
ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY OrderDate DESC) AS rn
FROM
Orders
)
UPDATE O
SET
IsSecondMostRecentOrder = 1
FROM
Orders O
INNER JOIN
RankedOrders RO ON O.OrderID = RO.OrderID
WHERE
RO.rn = 2;
Identifying and updating the second most recent order per customer.
UPDATE
operations based on ROW_NUMBER()
, always test your queries on a development environment with a backup of your data. Incorrect partitioning or ordering can lead to unintended data modifications.