How to Order a Query in SQL Server when using a Sequence to Number the Results

One common use case for sequences in SQL Server is to use them to number the results of a query. For example, we can add a column that has a number that increments with each row, similar to a row counter (but with a sequence that we define).

But we may encounter an issue if we try to order the results. The way to generate a new sequence number is with the NEXT VALUE FOR function. The problem is that this function can’t be used in queries that have the ORDER BY clause. Well, to be more specific, it can’t be used in queries that have the ORDER BY clause where it’s most commonly placed in SQL queries. Trying to order a query like this will result in an error.

The good news is that we can use it within an OVER clause. And the NEXT VALUE FOR function allows us to add an OVER clause with an ORDER BY sub clause.

Example

Here’s an example of ordering a query that uses a sequence to number the results:

SELECT
  NEXT VALUE FOR Sequence1 OVER (ORDER BY AlbumName ASC) AS AlbumNumber,
  AlbumName,
  Genre
FROM Albums
INNER JOIN Genres 
ON Albums.GenreId = Genres.GenreId;

Result:

AlbumNumber  AlbumName                 Genre  
-----------  ------------------------  -------
1            All Night Wrong           Jazz   
2            Along Came Jones          Pop    
3            Big Swing Face            Jazz   
4            Blue Night                Pop    
5            Casualties of Cool        Rock   
6            Epicloud                  Rock   
7            Eternity                  Pop    
8            Killers                   Rock   
9            Long Lost Suitcase        Pop    
10           No Prayer for the Dying   Rock   
11           No Sound Without Silence  Pop    
12           Piece of Mind             Rock   
13           Powerage                  Rock   
14           Powerslave                Rock   
15           Praise and Blame          Pop    
16           Scandinavia               Pop    
17           Singing Down the Lane     Country
18           Somewhere in Time         Rock   
19           The Sixteen Men of Tain   Jazz   
20           Ziltoid the Omniscient    Rock   

20 row(s) returned

Here, I used a sequence that starts at 1 and increments by 1. We were able to sort by the AlbumName column without any problems by specifying this in the OVER clause of the NEXT VALUE FOR function.

Let’s change it to a descending sort and run the query again:

SELECT
  NEXT VALUE FOR Sequence1 OVER (ORDER BY AlbumName DESC) AS AlbumNumber,
  AlbumName,
  Genre
FROM Albums
INNER JOIN Genres 
ON Albums.GenreId = Genres.GenreId;

Result:

AlbumNumber  AlbumName                 Genre  
-----------  ------------------------  -------
21           Ziltoid the Omniscient    Rock   
22           The Sixteen Men of Tain   Jazz   
23           Somewhere in Time         Rock   
24           Singing Down the Lane     Country
25           Scandinavia               Pop    
26           Praise and Blame          Pop    
27           Powerslave                Rock   
28           Powerage                  Rock   
29           Piece of Mind             Rock   
30           No Sound Without Silence  Pop    
31           No Prayer for the Dying   Rock   
32           Long Lost Suitcase        Pop    
33           Killers                   Rock   
34           Eternity                  Pop    
35           Epicloud                  Rock   
36           Casualties of Cool        Rock   
37           Blue Night                Pop    
38           Big Swing Face            Jazz   
39           Along Came Jones          Pop    
40           All Night Wrong           Jazz   

20 row(s) returned

As expected, the query results are now sorted by the AlbumName column in descending order, but the sequence numbers increment the same way regardless of how any other columns are sorted.

In this second example, the sequence numbers start at 21 because our previous example finished at 20.

Without the OVER Clause

As mentioned, if we try to sort the query without using the OVER clause, we’ll end up with an error:

SELECT
  NEXT VALUE FOR Sequence1 AS AlbumNumber,
  AlbumName,
  Genre
FROM Albums
INNER JOIN Genres 
ON Albums.GenreId = Genres.GenreId
ORDER BY AlbumName DESC;

Result:

Msg 11723, Level 15, State 1, Line 2
NEXT VALUE FOR function cannot be used directly in a statement that contains an ORDER BY clause unless the OVER clause is specified.