L'exemple suivant est le plus simple possible, même si toute solution doit être capable de s'adapter au nombre de n résultats supérieurs nécessaires:
Étant donné un tableau comme celui-ci ci-dessous, avec des colonnes de personne, de groupe et d'âge, comment obtiendriez-vous les 2 personnes les plus âgées de chaque groupe? (Les égalités au sein des groupes ne devraient pas donner plus de résultats, mais donner les 2 premiers par ordre alphabétique)
+ -------- + ------- + ----- + | Personne | Groupe | Age | + -------- + ------- + ----- + | Bob | 1 | 32 | | Jill | 1 | 34 | | Shawn | 1 | 42 | | Jake | 2 | 29 | | Paul | 2 | 36 | | Laura | 2 | 39 | + -------- + ------- + ----- +
Ensemble de résultats souhaité:
+ -------- + ------- + ----- + | Shawn | 1 | 42 | | Jill | 1 | 34 | | Laura | 2 | 39 | | Paul | 2 | 36 | + -------- + ------- + ----- +
REMARQUE: Cette question s'appuie sur une précédente - Obtenir des enregistrements avec une valeur maximale pour chaque groupe de résultats SQL groupés - pour obtenir une seule ligne supérieure de chaque groupe, et qui a reçu une excellente réponse spécifique à MySQL de @Bohemian:
select *
from (select * from mytable order by `Group`, Age desc, Person) x
group by `Group`
J'adorerais pouvoir développer cela, même si je ne vois pas comment.
Réponses:
Voici une façon de le faire, en utilisant
UNION ALL
(Voir SQL Fiddle avec Démo ). Cela fonctionne avec deux groupes, si vous avez plus de deux groupes, vous devez spécifier legroup
nombre et ajouter des requêtes pour chacungroup
:Il existe différentes façons de procéder, consultez cet article pour déterminer le meilleur itinéraire pour votre situation:
http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/
Éditer:
Cela peut également fonctionner pour vous, cela génère un numéro de ligne pour chaque enregistrement. En utilisant un exemple du lien ci-dessus, cela ne retournera que les enregistrements avec un numéro de ligne inférieur ou égal à 2:
Voir la démo
la source
SELECT
(et, en fait, les évalue parfois dans le désordre). La clé de la solution est de mettre toutes les affectations de variables dans une seule expression; voici un exemple: stackoverflow.com/questions/38535020/… .Dans d'autres bases de données, vous pouvez le faire en utilisant
ROW_NUMBER
. MySQL ne prend pas en chargeROW_NUMBER
mais vous pouvez utiliser des variables pour l'émuler:Le voir fonctionner en ligne: sqlfiddle
Edit Je viens de remarquer que bluefeet a publié une réponse très similaire: +1 pour lui. Cependant cette réponse présente deux petits avantages:
Je vais donc le laisser ici au cas où cela pourrait aider quelqu'un.
la source
JOIN (SELECT @prev := NULL, @rn := 0) AS vars
. J'ai l'idée de déclarer des variables vides, mais cela semble étranger pour MySql.Essaye ça:
DEMO
la source
a.person
.Que diriez-vous d'utiliser l'auto-adhésion:
Donne moi:
J'ai été fortement inspiré par la réponse de Bill Karwin à sélectionner les 10 meilleurs disques pour chaque catégorie
De plus, j'utilise SQLite, mais cela devrait fonctionner sur MySQL.
Autre chose: dans ce qui précède, j'ai remplacé la
group
colonne par unegroupname
colonne pour plus de commodité.Modifier :
Suite au commentaire du PO concernant les résultats de cravates manquants, j'ai augmenté la réponse de Snuffin pour montrer toutes les cravates. Cela signifie que si les derniers sont des égalités, plus de 2 lignes peuvent être renvoyées, comme indiqué ci-dessous:
Donne moi:
la source
ERROR 1242 (21000): Subquery returns more than 1 row
, probablement à cause duGROUP BY
. Lorsque j'exécute laSELECT MIN
sous - requête seule, elle génère trois lignes:34, 39, 112
et là, il semble que la deuxième valeur devrait être 36, pas 39.La solution Snuffin semble assez lente à exécuter lorsque vous avez beaucoup de lignes et que les solutions Mark Byers / Rick James et Bluefeet ne fonctionnent pas sur mon environnement (MySQL 5.6) car order by est appliqué après l'exécution de select, voici donc une variante des solutions Marc Byers / Rick James pour résoudre ce problème (avec une sélection imbriquée supplémentaire):
J'ai essayé une requête similaire sur une table ayant 5 millions de lignes et elle renvoie le résultat en moins de 3 secondes
la source
LIMIT 9999999
à n'importe quelle table dérivée avec unORDER BY
. Cela peut empêcherORDER BY
d'être ignoré.Regarde ça:
SQL Fiddle: http://sqlfiddle.com/#!2/cdbb6/15
la source
max(internal_version - 1)
- donc moins de stress :)Si les autres réponses ne sont pas assez rapides, essayez ce code :
Production:
la source
Je voulais partager cela parce que j'ai passé beaucoup de temps à chercher un moyen simple de l'implémenter dans un programme java sur lequel je travaille. Cela ne donne pas tout à fait la sortie que vous recherchez, mais c'est proche. La fonction appelée dans mysql
GROUP_CONCAT()
fonctionnait très bien pour spécifier le nombre de résultats à renvoyer dans chaque groupe. UtiliserLIMIT
ou l'une des autres façons sophistiquées d'essayer de faire celaCOUNT
ne fonctionnait pas pour moi. Donc, si vous êtes prêt à accepter une sortie modifiée, c'est une excellente solution. Disons que j'ai une table appelée «étudiant» avec les identifiants des étudiants, leur sexe et gpa. Disons que je veux top 5 gpas pour chaque sexe. Ensuite, je peux écrire la requête comme ceciNotez que le paramètre '5' lui indique le nombre d'entrées à concaténer dans chaque ligne
Et la sortie ressemblerait à quelque chose comme
Vous pouvez également modifier la
ORDER BY
variable et les ordonner d'une manière différente. Donc, si j'avais l'âge de l'élève, je pourrais remplacer le «gpa desc» par «age desc» et cela fonctionnera! Vous pouvez également ajouter des variables à l'instruction group by pour obtenir plus de colonnes dans la sortie. C'est donc juste une façon que j'ai trouvée qui est assez flexible et fonctionne bien si vous êtes d'accord avec la simple liste des résultats.la source
Dans SQL Server
row_numer()
est une fonction puissante qui peut obtenir le résultat facilement comme ci-dessousla source
Il y a une très bonne réponse à ce problème chez MySQL - Comment obtenir les N premières lignes par chaque groupe
Sur la base de la solution dans le lien référencé, votre requête serait comme:
où
n
est letop n
etyour_table
est le nom de votre table.Je pense que l'explication dans la référence est vraiment claire. Pour une référence rapide, je vais le copier et le coller ici:
la source