Obtenir des n premiers enregistrements pour chaque groupe de résultats groupés
Suivantes est la plus simple possible exemple, bien que toute solution devrait être en mesure à l'échelle par le nombre n d'obtenir les meilleurs résultats sont nécessaires:
Donné un tableau comme celui ci-dessous, avec la personne, le groupe et l'âge des colonnes, comment voulez-vous obtenir les 2 plus anciens de personnes dans chaque groupe? (Les liens au sein de groupes ne doivent pas céder plus de résultats, mais de donner les 2 premiers dans l'ordre alphabétique)
+--------+-------+-----+ | Personne | Groupe | Âge | +--------+-------+-----+ | Bob| 1 | 32 | | Jill| 1 | 34 | | Shawn| 1 | 42 | | Jake| 2 | 29 | | Paul| 2 | 36 | | Laura| 2 | 39 | +--------+-------+-----+
Résultats souhaités:
+--------+-------+-----+ | Shawn| 1 | 42 | | Jill| 1 | 34 | | Laura| 2 | 39 | | Paul| 2 | 36 | +--------+-------+-----+
REMARQUE: Cette question s'appuie sur un précédent- Obtenir des enregistrements avec valeur maximale pour chaque groupe d'regroupés les résultats SQL - pour l'obtention d'une seule rangée du haut, de chaque groupe, et qui a reçu une grande spécifique à MySQL réponse de @Bohème:
select *
from (select * from mytable order by `Group`, Age desc, Person) x
group by `Group`
Aimerais être en mesure de construire ce, bien que je ne vois pas comment.
Cochez cette exemple. Il est assez proche de ce que vous demandez: stackoverflow.com/questions/1537606/...
OriginalL'auteur Yarin | 2012-08-24
Vous devez vous connecter pour publier un commentaire.
Ici est une façon de le faire, à l'aide de
UNION ALL
(Voir SQL jouer avec la Démo). Cela fonctionne avec les deux groupes, si vous avez plus de deux groupes, alors vous devez spécifier legroup
nombre et ajouter des requêtes pour chaquegroup
:Il existe une variété de façons de le faire, voir 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/
Edit:
Cela pourrait fonctionner pour vous aussi, il génère un numéro de ligne pour chaque enregistrement. À l'aide d'un exemple à partir du lien ci-dessus vous obtiendrez seulement les enregistrements avec un numéro de ligne est inférieure ou égale à 2:
Voir Démo
oui, il faudrait, et c'Est pourquoi j'ai dit que vous devez spécifier dans les deux groupes. Il serait devenu laid.
Je crois que j'ai trouvé une meilleure solution, voir mon edit
Une remarque pour tous ceux qui lisent ceci: La version est l'variables est proche d'être correcte. Toutefois, MySQL ne garantit pas l'ordre d'évaluation des expressions dans le
SELECT
(et, en fait, parfois, évalue les out-of-order). La clé de la solution est de mettre toutes les affectations de variables dans une expression unique; en voici un exemple: stackoverflow.com/questions/38535020/....Mise à jour de ma réponse, merci pour le tuyau. Il a également pris beaucoup trop de temps pour me mettre à jour.
OriginalL'auteur Taryn
Dans d'autres bases de données que vous pouvez faire cela en utilisant
ROW_NUMBER
. MySQL ne supporte pasROW_NUMBER
mais vous pouvez utiliser des variables pour l'émuler:Voir en ligne: sqlfiddle
Modifier je viens de remarquer que bluefeet posté un très semblables réponse: +1 pour lui. Cependant cette réponse a deux petits avantages:
Donc je vais le laisser ici au cas où ça pourrait aider quelqu'un.
Pourquoi est-ce que cette Requête a fonctionné? pastebin.com/u17NRM8B
+1. Cela a fonctionné pour moi. Vraiment propre et au point de réponse. Pouvez-vous nous expliquer comment cela fonctionne? Ce qui est la logique derrière cela?
Solution sympa mais il semble que cela ne fonctionne pas dans mon environnement (MySQL 5.6) parce que la clause order by est appliquée après le sélectionner afin de ne pas retourner le résultat haut de la page, voir mon autre solution pour résoudre ce problème
Cela fonctionne très bien pour moi dans MySQL 5.7, mais ce serait génial si quelqu'un pouvait expliquer comment cela fonctionne
OriginalL'auteur Mark Byers
Essayez ceci:
DÉMO
Hm, pas sûr si c'est plus élégant. Mais à en juger par la voix, je suppose que bluefeet pourrait avoir la meilleure solution.
Il y a un problème avec cela. Si il y a égalité pour la deuxième place dans le groupe, un seul top résultat est retourné. Voir modifié démo
Ce n'est pas un problème si c'est souhaité. Vous pouvez définir l'ordre de
a.person
.non, il n'est pas de travail dans mon cas, ni la DÉMO de travail
OriginalL'auteur snuffn
Comment sur l'utilisation de l'auto-assemblage:
me donne:
J'ai été fortement inspiré par la réponse de Bill Karwin à Select top 10 des dossiers pour chaque catégorie
Aussi, je suis en utilisant SQLite, mais cela doit fonctionner sur MySQL.
Une autre chose: dans le ci-dessus, j'ai remplacé le
group
colonne avec ungroupname
colonne pour plus de commodité.Modifier:
Suivi des OP de commentaire concernant l'absence de cravate résultats, j'ai incrémenté sur snuffin de réponse pour afficher tous les liens. Cela signifie que si les derniers sont des liens, plus de 2 lignes peuvent être retournés, comme indiqué ci-dessous:
me donne:
Que pensez-vous de Snuffin de réponse? Je suis en train de comparer les deux
Il y a un problème avec cela. Si il y a égalité pour la deuxième place dans le groupe, un seul top résultat est retourné Voir démo
l'exigence de départ était que chaque groupe de restituer les n résultats, avec tous les liens résolus par ordre alphabétique
Le modifier pour inclure les liens ne fonctionne pas pour moi. Je reçois
ERROR 1242 (21000): Subquery returns more than 1 row
, sans doute à cause de laGROUP BY
. Quand j'execute leSELECT MIN
sous-requête seul, il génère trois lignes:34, 39, 112
et là, il semble que la deuxième valeur doit être 36, pas 39.OriginalL'auteur
Check this out:
SQL Violon: http://sqlfiddle.com/#!2/cdbb6/15
de votre tête jusqu'à Travesty3 - upvoted votre effort, merci
J'ai dû trouver un numéro de version interne qui est 1 de moins que l'actuel cela m'a donné la réponse pour ce faire:
max(internal_version - 1)
- donc moins de stress 🙂OriginalL'auteur Travesty3
Snuffin solution semble assez lent à exécuter lorsque vous avez beaucoup de lignes et de Marque Byers/Rick James et Bluefeet solutions ne fonctionne pas sur mon environnement (MySQL 5.6), car l'ordre est appliqué après l'exécution de sélectionner, voici donc une variante de Marc Byers/Rick James solutions pour résoudre ce problème (avec un supplément de imbriquées à choisir):
J'ai essayé de requête similaire sur une table de 5 millions de lignes et il renvoie le résultat en moins de 3 secondes
Ajouter
LIMIT 9999999
à toute table dérivée avec unORDER BY
. Ce prévenir laORDER BY
d'être ignoré.J'ai couru une requête similaire sur une table contenant quelques milliers de lignes, et il a fallu 60 secondes pour retourner un résultat, donc... merci pour le post, c'est un début pour moi. (ETA: jusqu'à 5 secondes. Bon!!!)
OriginalL'auteur Laurent PELE
Si les autres réponses ne sont pas assez rapides Donner ce code un essai:
De sortie:
maxmind.com/en/worldcities -- je le trouve pratique pour expérimenter avec lat/lng recherches, de requêtes, de partitionnement, etc. Il est assez grand pour être intéressant, mais lisible assez pour comprendre les réponses. Les Canadiens sous-ensemble est très pratique pour ce genre de question. (Moins de provinces, de villes des états-unis.)
OriginalL'auteur Rick James
Je voulais partager cela car j'ai passé un long moment à la recherche d'un moyen facile de l'appliquer dans un programme java, je travaille sur. Ce n'est pas tout à fait donner la sortie que vous recherchez, mais ses proches. La fonction mysql appelée
GROUP_CONCAT()
a vraiment bien travaillé pour spécifier le nombre de résultats à retourner dans chaque groupe. À l'aide deLIMIT
ou de toute autre fantaisie de façons d'essayer de le faire avecCOUNT
ne fonctionne pas pour moi. Donc, si vous êtes prêt à accepter une modification de la sortie, c'est une excellente solution. Disons que j'ai une table appelée "étudiant" avec id d'étudiants, de leur sexe, et de la gpa. Disons que je veux le top 5 gpas pour chacun des sexes. Ensuite, je peux écrire la requête de ceNotez que le paramètre "5", dit-il combien d'entrées pour concaténer dans chaque ligne
Et la sortie devrait ressembler à quelque chose comme
Vous pouvez également modifier la
ORDER BY
variable et de leur ordonner d'une manière différente. Donc, si j'avais l'âge de l'étudiant je pouvais remplacer la "gpa desc' avec 'âge desc' et ça marche! Vous pouvez également ajouter des variables à l'instruction group by pour obtenir plus de colonnes dans le résultat. Donc, c'est juste un moyen que j'ai trouvé qui est assez flexible et fonctionne bien si vous êtes ok avec juste la liste des résultats.OriginalL'auteur Jon Bown
Dans SQL Server
row_numer()
est une fonction puissante qui peut entraîner facilement comme ci-dessousque signifie " être GA? Les fonctions de la fenêtre (dev.mysql.com/doc/refman/8.0/en/window-functions.html) a résolu mon problème très bien.
signifie "généralisé". Il est tech-parler", "prêt pour le prime time", ou "libéré". Ils sont à travers le développement de la version et mettra l'accent sur les bug qu'ils ont manqué. Ce lien explique MySQL 8.0 de la mise en œuvre, qui peut être différent de MariaDB 10.2 mise en œuvre.
OriginalL'auteur Prakash
Il y a vraiment une belle réponse à ce problème à MySQL - Comment Obtenir les N premières Lignes par Chaque Groupe
Basé sur 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 de la référence est vraiment clair. Pour une référence rapide, je vais le copier et le coller ici:
Difficile de dire quel poste (Débordement de Pile ou SQLlines) a été le premier
Le mien a été posté le Fév, 2015. Je ne vois pas d'horodatage ou de nom sur SQLlines. MySQL blogs ont été autour assez longtemps pour certains d'entre eux sont hors de date, et doit être supprimé -- les gens sont en citant la mauvaise information.
OriginalL'auteur swdon