Question

J'ai deux tables players et scores.

Je veux générer un rapport qui ressemble à quelque chose comme ceci:

player    first score             points
foo       2010-05-20              19
bar       2010-04-15              29
baz       2010-02-04              13

En ce moment, ma requête ressemble à ceci:

select p.name        player,
       min(s.date)   first_score,
       s.points      points    
from  players p    
join  scores  s on  s.player_id = p.id    
group by p.name, s.points

J'ai besoin du s.points qui est associé à la ligne qui retourne min(s.date). Est-ce que cela se produise avec cette requête? Autrement dit, comment puis-je être certain que je reçois la valeur s.points correcte pour la ligne jointe?

Note Side: J'imagine que cela est lié en quelque sorte à l'absence de MySQL dense classement. Quelle est la meilleure solution ici?

Était-ce utile?

La solution

Ceci est le plus grand-n-par groupe problème qui revient souvent sur le débordement de pile.

Voici ma réponse habituelle:

select
  p.name        player,
  s.date        first_score,
  s.points      points

from  players p

join  scores  s
  on  s.player_id = p.id

left outer join scores  s2
  on  s2.player_id = p.id
      and s2.date < s.date

where
  s2.player_id is null

;

En d'autres termes, score donné s, essayer de trouver un s2 score pour le même joueur, mais avec une date antérieure. Si aucun score antérieure est trouvée, s est plus tôt un.


Re vos commentaires sur les liens: Vous devez avoir une politique pour lequel utiliser en cas d'égalité. Une possibilité est que si vous utilisez les clés primaires auto-incrémentée, celui avec le moins de valeur est la première. Voir le terme supplémentaire dans la jointure externe ci-dessous:

select
  p.name        player,
  s.date        first_score,
  s.points      points

from  players p

join  scores  s
  on  s.player_id = p.id

left outer join scores  s2
  on  s2.player_id = p.id
      and (s2.date < s.date or s2.date = s.date and s2.id < s.id)

where
  s2.player_id is null

;

En gros vous devez ajouter des termes de bris d'égalité jusqu'à ce que vous descendez à une colonne qui est garanti d'être unique, au moins pour le joueur donné. La clé primaire de la table est souvent la meilleure solution, mais je l'ai vu des cas où une autre colonne était appropriée.

En ce qui concerne les commentaires que je partageais avec @OMG Ponies, rappelez-vous que ce type de prestations de requête énormement de l'index droit.

Autres conseils

La plupart des SGBDR ne sera même pas vous permettent d'inclure des colonnes non agrégées dans votre clause SELECT lorsque vous utilisez GROUP BY. En MySQL, vous vous retrouverez avec des valeurs de lignes aléatoires pour vos colonnes non agrégées. Ceci est utile si vous avez réellement la même valeur dans une colonne particulière pour toutes les lignes. Par conséquent, il est bien que MySQL ne nous empêche pas, mais il est une chose importante à comprendre.

Un chapitre entier est consacré à cette SQL Antipatterns .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top