Click here to Skip to main content
15,879,348 members
Articles / Database Development / SQL Server

How to Use ROW_NUMBER() to Enumerate and Partition Records in SQL Server

Rate me:
Please Sign up or sign in to vote.
4.77/5 (44 votes)
31 Dec 2011CPOL3 min read 686.9K   41   24
Use ROW_NUMBER() to enumerate and partition records in SQL Server

I had a situation recently where I had a table full of people records, where the people were divided into families. The business logic that needed to be followed was that I had to assign a “Twin Code” to each record. This meant that for each family in the database, if two or more members were born on the same day, they should be treated as twins. The twins should be assigned a number enumerating them in order of birth. If the member was not a twin, they should just receive the twin code of 1.

Here’s an example table:

PersonID FamilyID FirstName LastName DateOfBirth
1 1 Joe Johnson 2000-10-23 13:00:00
2 1 Jim Johnson 2001-12-15 05:45:00
3 2 Karly Matthews 2000-05-20 04:00:00
4 2 Kacy Matthews 2000-05-20 04:02:00
5 2 Tom Matthews 2001-09-15 11:52:00

There are lots of ways to achieve the desired result, but the simplest is to just use a simple SELECT statement combined with the ROW_NUMBER() function with a couple parameters as to how to number the rows!

ROW_NUMBER() provides you with the number of a row in a given recordset, where you provide details on how to number the records. For example, if I just had to number the records above based solely upon the date of birth (ignoring families), then I would use this query:

SQL
SELECT
     [PersonID]
    ,[FamilyID]
    ,[FirstName]
    ,[LastName]
    ,[DateOfBirth]
    ,ROW_NUMBER() over (ORDER BY DateOfBirth) AS Number
FROM
	People
ORDER BY
	PersonID

This just tells the ROW_NUMBER() function to order its numbering ascending by DateOfBirth. Notice that I apply an order myself later on in the query, which is different than the row_number() order. I would get these results:

PersonID FamilyID FirstName LastName DateOfBirth Number
1 1 Joe Johnson 2000-10-23 13:00:00 3
2 1 Jim Johnson 2001-12-15 05:45:00 5
3 2 Karly Matthews 2000-05-20 04:00:00 1
4 2 Kacy Matthews 2000-05-20 04:02:00 2
5 2 Tom Matthews 2001-09-15 11:52:00 4

The number field that is assigned to each record is in the order of DateOfBirth.

Ordering my numbering by DateOfBirth is just half of the picture. I also need to “group” the records by the FamilyID. This is where a clause in T-, SQL that you might not be very familiar with comes into play: “PARTITION BY”. The PARTITION BY clause allows us to group the results within the call to ROW_NUMBER() without grouping them ourselves via a GROUP BY. It just tells the ROW_NUMBERR what groupings to use when it does its counting.

Here is our final SQL statement, which achieves the business logic we wanted to implement.

SQL
SELECT
       [PersonID]
     [FamilyID]
      ,[FirstName]
      ,[LastName]
      ,[DateOfBirth]
      ,ROW_NUMBER() over(PARTITION BY FamilyID,
                         CONVERT(NVARCHAR(25), DateOfBirth, 111)
                         ORDER BY DateOfBirth ASC) TwinCode

  FROM [People]
ORDER BY	PersonID

IIn the ROW_NUMBER function above, I am doing several things. I’m grouping on FamilyID, and also grouping on a converted DateOfBirth. I convert the DateOfBirth to an nvarchar using the 111 conversion code, because that gets results like ‘2009/10/11′ and ‘2009/10/12′ which can easily be grouped by to achieve distinct dates.

Grouping on the Family, DateOfBirth, and then sorting by DateOfBirth ascending achieves the desired result for the ROW_NUMBER. Here are the results of the query:

PersonID FamilyID FirstName LastName DateOfBirth TwinCode
1 1 Joe Johnson 2000-10-23 13:00:00 1
2 1 Jim Johnson 2001-12-15 05:45:00 1
3 2 Karly Matthews 2000-05-20 04:00:00 1
4 2 Kacy Matthews 2000-05-20 04:02:00 2
5 2 Tom Matthews 2001-09-15 11:52:00 1

As you can see, the two people who qualify as twins above (Karly and Kacy) are enumerated correctly, with Karly receiving a 1 and Kacy receiving a 2. All the records that are not twins properly receive a 1.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) LBMC Technologies
United States United States
I've been developing software since I was 9 years old, in BASIC on a Precomputer 2000. OK, that's a stretch, but hopefully some of the stuff that I learned from that little toy have helped my professional career.

I have a bachelors degree in computer science from MTSU. Currently, I am employed as a senior software developer for LBMC in Nashville, TN. We serve as consultant developers for clients across the southeastern United States, developing mostly in Microsoft .Net with Microsoft SQL Server.

I greatly enjoy my job and my hobbies lie in open source software and in teaching others how to be better programmers. I have a beautiful wife, 2 dogs (a dachshund and an olde-english bulldog) and a cat.

Comments and Discussions

 
QuestionQuestion Pin
Member 1299990613-Feb-17 23:36
Member 1299990613-Feb-17 23:36 
QuestionThanks! Pin
Member 128328124-Nov-16 4:40
Member 128328124-Nov-16 4:40 
QuestionThank you! You saved me Pin
Member 922453021-Apr-15 2:53
Member 922453021-Apr-15 2:53 
GeneralMy vote of 5 Pin
Raghunadh S V6-Mar-15 20:03
Raghunadh S V6-Mar-15 20:03 
GeneralMy vote of 5 Pin
CHill6019-Feb-15 22:33
mveCHill6019-Feb-15 22:33 
GeneralWonderful Explanation! Pin
Member 114355987-Feb-15 16:20
Member 114355987-Feb-15 16:20 
AnswerTHANKS MAN!!! Pin
PH Patrício10-Dec-14 2:20
PH Patrício10-Dec-14 2:20 
GeneralVote Of 5 Pin
DiponRoy22-Sep-14 8:24
DiponRoy22-Sep-14 8:24 
GeneralWell done Pin
karenpayne10-Jul-14 8:29
karenpayne10-Jul-14 8:29 
QuestionI don't see the how the Twin Code column helps Pin
Developer_4603827-Aug-13 7:07
Developer_4603827-Aug-13 7:07 
AnswerRe: I don't see the how the Twin Code column helps Pin
Grossmeister14-Oct-13 3:36
Grossmeister14-Oct-13 3:36 
GeneralMy vote of 5 Pin
Tien Xuan Le17-Jun-13 7:54
professionalTien Xuan Le17-Jun-13 7:54 
GeneralMy vote of 5 Pin
pablocci28-May-13 6:15
pablocci28-May-13 6:15 
GeneralMy vote of 5 Pin
nyaung15-Mar-13 19:27
nyaung15-Mar-13 19:27 
GeneralMy vote of 5 Pin
wsc09184-Dec-12 21:32
wsc09184-Dec-12 21:32 
GeneralMy vote of 4 Pin
Ivan Dario Ospina17-Jul-12 11:13
Ivan Dario Ospina17-Jul-12 11:13 
GeneralMy vote of 5 Pin
Corporal Agarn14-Feb-12 7:21
professionalCorporal Agarn14-Feb-12 7:21 
QuestionThere is a flow in this algorithm... Pin
Georgi Hadzhigeorgiev4-Jan-12 0:02
Georgi Hadzhigeorgiev4-Jan-12 0:02 
AnswerRe: There is a flow in this algorithm... Pin
Dave C Andrews9-Jan-12 5:13
Dave C Andrews9-Jan-12 5:13 
AnswerRe: There is a flow in this algorithm... Pin
stevehiner7-Nov-14 9:49
stevehiner7-Nov-14 9:49 
GeneralMy vote of 5 Pin
Jan Steyn1-Jan-12 23:22
Jan Steyn1-Jan-12 23:22 
GeneralMy vote of 5 Pin
merlin9811-Jan-12 3:44
professionalmerlin9811-Jan-12 3:44 
Great article, explains exactly what the title says. Interesting idea using row_number and partition by
SuggestionOff Topic - UserID Pin
thatraja31-Dec-11 5:28
professionalthatraja31-Dec-11 5:28 
GeneralRe: Off Topic - UserID Pin
Dave C Andrews3-Jan-12 8:16
Dave C Andrews3-Jan-12 8:16 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.