snippetsqlMajor
How to get the MAX row
Viewed 0 times
themaxgethowrow
Problem
In SQL Server I've always found it a pain to get the max rows for a dataset, I'm looking for a list of the methods to retrieve the max rows with some guidance on performance and maintainability.
Sample Table:
Gives:
If I want to retrieve the oldest person (group by name) full details, what methods can I use?
Desired output:
Sample Table:
DECLARE @Test TABLE (ID INT IDENTITY(1,1), name VARCHAR(50),
dateOfBirth DATETIME, TaxNumber varchar(10))
INSERT INTO @Test (name, dateOfBirth, TaxNumber)
SELECT 'Fred', convert(datetime, '25/01/1976', 103), '123' UNION ALL
SELECT 'Bob', convert(datetime, '03/03/1976', 103), '234' UNION ALL
SELECT 'Jane', convert(datetime, '13/06/1996', 103), '345' UNION ALL
SELECT 'Fred', convert(datetime, '14/02/1982', 103), '456' UNION ALL
SELECT 'Bob', convert(datetime, '25/10/1983', 103), '567' UNION ALL
SELECT 'Jane', convert(datetime, '12/04/1995', 103), '678' UNION ALL
SELECT 'Fred', convert(datetime, '03/03/1976', 103), '789'
select * from @TestGives:
ID name dateOfBirth TaxNumber
----------- --------- ----------------------- ----------
1 Fred 1976-01-25 00:00:00.000 123
2 Bob 1976-03-03 00:00:00.000 234
3 Jane 1996-06-13 00:00:00.000 345
4 Fred 1982-02-14 00:00:00.000 456
5 Bob 1983-10-25 00:00:00.000 567
6 Jane 1995-04-12 00:00:00.000 678
7 Fred 1976-03-03 00:00:00.000 789If I want to retrieve the oldest person (group by name) full details, what methods can I use?
Desired output:
ID name dateOfBirth TaxNumber
----------- --------- ----------------------- ----------
1 Fred 1976-01-25 00:00:00.000 123
2 Bob 1976-03-03 00:00:00.000 234
6 Jane 1995-04-12 00:00:00.000 678Solution
Two usual methods: aggregate and ranking function.
The aggregate works on SQL Server 2000. Both ways can use a CTE or derived table
For performance, I've found the aggregate works better. However, it looks like SQL Server 2008 ranking functions run far better than on SQL Server 2005. I'm not using SQL Server 2008 day to day yet (large dinsoaur corporate) so can't comment.
There are 2 relevant SO Questions but I can't find them currently. One is a questions about high logical IO with ranking functions, another is testing of ranking in comments over SQL 2k5 vs 2k8. Sorry.
The aggregate works on SQL Server 2000. Both ways can use a CTE or derived table
For performance, I've found the aggregate works better. However, it looks like SQL Server 2008 ranking functions run far better than on SQL Server 2005. I'm not using SQL Server 2008 day to day yet (large dinsoaur corporate) so can't comment.
There are 2 relevant SO Questions but I can't find them currently. One is a questions about high logical IO with ranking functions, another is testing of ranking in comments over SQL 2k5 vs 2k8. Sorry.
--aggregate + CTE
;WITH cOldest AS
(
SELECT name, MIN(dateOfBirth) AS MinDOB FROM @Test GROUP BY name
)
SELECT
T.*
FROM
@Test T
JOIN
cOldest C ON T.name = C.name AND T.dateOfBirth = C.MinDOB
ORDER BY
T.ID
--aggregate + derived table
SELECT
T.*
FROM
@Test T
JOIN
(
SELECT name, MIN(dateOfBirth) AS MinDOB FROM @Test GROUP BY name
) C ON T.name = C.name AND T.dateOfBirth = C.MinDOB
ORDER BY
T.ID
--ranking + CTE
;WITH cOldest AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY name ORDER BY dateOfBirth) AS rnDOB FROM @Test
)
SELECT
C.*
FROM
cOldest C
WHERE
C.rnDOB = 1
ORDER BY
C.ID
--ranking + derived table
SELECT
C.*
FROM
(SELECT *, ROW_NUMBER() OVER (PARTITION BY name ORDER BY dateOfBirth) AS rnDOB FROM @Test) C
WHERE
C.rnDOB = 1
ORDER BY
C.IDCode Snippets
--aggregate + CTE
;WITH cOldest AS
(
SELECT name, MIN(dateOfBirth) AS MinDOB FROM @Test GROUP BY name
)
SELECT
T.*
FROM
@Test T
JOIN
cOldest C ON T.name = C.name AND T.dateOfBirth = C.MinDOB
ORDER BY
T.ID
--aggregate + derived table
SELECT
T.*
FROM
@Test T
JOIN
(
SELECT name, MIN(dateOfBirth) AS MinDOB FROM @Test GROUP BY name
) C ON T.name = C.name AND T.dateOfBirth = C.MinDOB
ORDER BY
T.ID
--ranking + CTE
;WITH cOldest AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY name ORDER BY dateOfBirth) AS rnDOB FROM @Test
)
SELECT
C.*
FROM
cOldest C
WHERE
C.rnDOB = 1
ORDER BY
C.ID
--ranking + derived table
SELECT
C.*
FROM
(SELECT *, ROW_NUMBER() OVER (PARTITION BY name ORDER BY dateOfBirth) AS rnDOB FROM @Test) C
WHERE
C.rnDOB = 1
ORDER BY
C.IDContext
StackExchange Database Administrators Q#1002, answer score: 21
Revisions (0)
No revisions yet.