To generate a numbering from an order of rows, use row_number()
or rank()
. The problem is, row_number()
does not guarantee the original order will be preserved. You could try this:
select
[id],
row_number() over (partition by id, order by (select 1)) as [rank]
from @t
However, you will find the results are not in the original order and somewhat confusing:
id rank
3 1
3 2
3 3
4 1
4 2
5 1
5 2
To preserve the original row order, you could build a temporary table or table variable with an identity
column. Select a row_number()
partitioned by id
from there:
declare @t table ([tkey] int identity(1,1) primary key clustered, [id] int)
insert into @t (id) values (4), (4), (5), (3), (5), (3), (3)
select
[id],
row_number() over (partition by [Id] order by [tkey]) as [rank]
from @t
order by [tkey]
Note that the final order by [tkey]
really is necessary. The query has the desired results:
id rank
4 1
4 2
5 1
3 1
5 2
3 2
3 3
Here is a Common Table Expression (CTE) approach. The CTE adds a row_number()
to maintain the rows in the original order. (This is the equivalent of the identity
column in the previous example.) The actual ranking comes with the second row_number()
when it does a partition by id
. This causes the 1st 4 gets 1, the 2nd 4 gets 2, etc.
The second row_number()
must be ordered by the original order to rank correctly, but this is still not enough to preserve the order in the output. A final order by
ensures the ending order is the same.
declare @t table (id int)
insert into @t (id) values (4), (4), (5), (3), (5), (3), (3)
;with [tRows] (rownum, id) as
(
select
row_number() over (order by (select 1)) as [rownum],
[id]
from @t
)
select
[id],
row_number() over (partition by id order by [rownum]) as [rank]
from [tRows]
order by [rownum]
This query also has the desired results:
id rank
4 1
4 2
5 1
3 1
5 2
3 2
3 3
In this example, you could use rank()
instead of the second row_number()
. The difference between the functions is explained well in this question. rank()
would not work the same if, somehow, there were duplicate row numbers generated by the first row_number()
, but that cannot happen.