I am using SSMS 2008, trying to select just one row/client. I need to select the following columns: client_name, end_date, and program. Some clients have just one client row. But others have multiple.
For those clients with multiple rows, they normally have different end_date and program. For instance:
CLIENT PROGRAM END_DATE
a b c
a d e
a f g
h d e
h f NULL
This is a real simplified version of the actual data. As you will see, different clients can be in the same program (“d”). But the same client cannot be in the same program more than one time.
Also the tricky thing is that the end_date can be NULL, so when I tried selecting those clients with > 1 row, I added a HAVING statement > 1. But this eliminated all of my NULL End_date rows.
To sum up, I want one row per client. So those clients with only one row total + those clients listed above with the following criteria:
- Select only the row where either the
End_dateis greatest or NULL. (In most cases theend_dateis null for these clients).
How can I achieve this with as little logic as possible?
On SQL Server 2005 and up, you can use a Common Table Expression (CTE) combined with the
ROW_NUMBER()andPARTITION BYfunction. This CTE will “partition” your data by one criteria – in your case byClient, creating a “partition” for each separate client. TheROW_NUMBER()will then number each partition ordered by another criteria – here I created aDATETIME– and assigns numbers from 1 on up, separately for each partition.So in this case, ordering by
DATETIME DESC, the newest row gets numbered as 1 – and that’s the fact I use when selecting from the CTE. I used theISNULL()function here to assign those rows that have a NULLend_datesome arbitrary value to “get them in order”. I wasn’t quite sure if I understood your question properly: did you want to select the NULL rows over those with a givenend_Date, or did you want to give precedence to an existingend_Datevalue over NULL?This will select the most recent row for each client (for each “partition” of your data):
Results in an output of: