2010-04-17 7 views
20

Possible en double:
Retrieving the last record in each groupSQL: Recherche de l'enregistrement max par groupe

J'ai une table, qui a trois champs et des données.

 
Name , Top , Total 
cat , 1 , 10 
dog , 2 ,  7 
cat , 3 , 20 
horse , 4 ,  4 
cat , 5 , 10 
dog , 6 ,  9 

Je veux sélectionner l'enregistrement qui a la plus haute valeur de Total pour chaque Name, donc mon résultat devrait ressembler à ceci:

 
Name , Top , Total 
cat , 3 , 20 
horse , 4 ,  4 
Dog , 6 ,  9 

J'ai essayé groupe par ordre de nom par le total, mais il donne premier record du groupe par résultat. Quelqu'un peut-il me guider, s'il vous plaît?

+3

I Je me demande combien de doublons il y a pour cette requête - certainement beaucoup m plus qu'un seul. Voir les 60+ questions marquées «plus grand-n-par-groupe» (pour les cas n = 1). –

+0

@Jonathan: Ceci est la "question éternelle" dans le domaine des questions SQL débutant. Il y en a un tous les jours sur SO. – Tomalak

Répondre

27
select 
    Name, Top, Total 
from 
    sometable 
where 
    Total = (select max(Total) from sometable i where i.Name = sometable.Name) 

ou

select 
    Name, Top, Total 
from 
    sometable 
    inner join (
    select max(Total) Total, Name 
    from sometable 
    group by Name 
) as max on max.Name = sometable.Name and max.Total = sometable.Total 
+0

salut monsieur, merci pour votre réponse rapide. J'ai également créé une requête tout à l'heure, et c'est ce qui me donne un résultat parfait. ici est ma requête Nom select, Top, au total des animaux où total (SELECT max (total) FROM 'animals' groupe par nom) groupe par nom ma question est, ce qui est plus efficace, le vôtre ou le mien quand la table contient 2 millions de données? merci encore pour votre réponse. – user319088

+0

Lequel est le plus efficace? Définissez les index appropriés sur votre table et essayez-le. En dehors de cela, votre 'WHERE total in (...)' est faux. Vous le constateriez rapidement une fois que vous aurez essayé * avec * des millions d'enregistrements et pas seulement une main pleine. – Tomalak

+2

La deuxième requête est probablement plus efficace que la première car la première utilise une sous-requête corrélée qui peut être exécutée plusieurs fois au lieu d'une seule fois dans la deuxième version. –

5

Vous pouvez essayer quelque chose comme

SELECT s.* 
FROM sometable s INNER JOIN 
     (
      SELECT Name, 
        MAX(Total) MTotal 
      FROM sometable 
      GROUP BY Name 
     ) sMax ON s.Name = sMax.Name 
       AND s.Total = sMax.MTotal 
0

ou en utilisant une clause EXISTS, Wich retourne la seule ligne qui existe dans les deux tables

SELECT * from sometable T 
where exists 
(select 1 
from (SELECT nombre, max(total) as total FROM sometable TT 
    GROUP by nombre) TT 
where T.name=TT.name 
and T.total=TT.total 
) 
+1

Cela fonctionnera, avec la mise en garde à ce sujet étant coûteux sur les grandes tables avec un optimiseur naïf qui ne parvient pas à exécuter la sous-requête corrélée une seule fois. –

+1

@Jonathan +1 uniquement pour l'utilisation du diacritique i dans "naïve". :-) – Tomalak