Comment obtenir la ligne MAX

20

Dans SQL Server, j'ai toujours trouvé difficile d'obtenir les lignes max pour un ensemble de données, je cherche une liste des méthodes pour récupérer les lignes max avec quelques conseils sur les performances et la maintenabilité.

Exemple de tableau:

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 @Test

Donne:

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 789

Si je veux récupérer les détails complets de la personne la plus âgée (regrouper par nom), quelles méthodes puis-je utiliser?

Sortie désirée:

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 678
Andrew Bickerton
la source

Réponses:

20

Deux méthodes habituelles: fonction d'agrégation et de classement.

L'agrégat fonctionne sur SQL Server 2000. Les deux méthodes peuvent utiliser un CTE ou une table dérivée

Pour les performances, j'ai trouvé que l'agrégat fonctionne mieux. Cependant, il semble que les fonctions de classement de SQL Server 2008 fonctionnent bien mieux que sur SQL Server 2005. Je n'utilise pas encore SQL Server 2008 au jour le jour (grande entreprise dinsoaur), donc je ne peux pas commenter.

Il y a 2 questions SO pertinentes, mais je ne les trouve pas actuellement. L'une est une question sur les E / S logiques élevées avec des fonctions de classement, une autre teste le classement dans les commentaires sur SQL 2k5 vs 2k8. Pardon.

--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.ID
gbn
la source