SELECT LIMIT 1 par valeur de colonne?

10

Disons que j'ai le tableau suivant

-----------------------------
| user_id   | comment       |
-----------------------------
| 2         | thats cool    |
| 2         | awesome       |
| 3         | i hate this   |
| 3         | okay          |
| 6         | this is weird |
| 6         | hello?        |
| 6         | what is it    |
| 9         | how are you   |
| 16        | too slow      |
| 16        | yes           |
| 17        | alrighty      |
-----------------------------

Comment pouvez-vous sélectionner une ligne par user_id? Mes résultats seraient donc:

-----------------------------
| user_id   | comment       |
-----------------------------
| 2         | thats cool    |
| 3         | i hate this   |
| 6         | this is weird |
| 9         | how are you   |
| 16        | too slow      |
| 17        | alrighty      |
-----------------------------

Est-ce possible avec une seule requête efficace? Ou une sous-sélection est-elle nécessaire? Est-il possible de l'utiliser DISTINCTd'une manière ou d'une autre sur une seule colonne?

Jake Wilson
la source

Réponses:

9

Voilà à quoi GROUP BYsert. Obtenez une ligne (par groupe). Dans ce cas, il affichera toutes les différentes user_idvaleurs et pour le reste des colonnes, vous pouvez (devez) utiliser des fonctions d' agrégation comme MIN(), MAX(), AVG(), SUM()que vous aurez plus d'une valeur par groupe et un seul peut être montré.

SELECT
    user_id
  , MIN(comment) AS comment  -- it will show the first in alphabetical order  
                             -- you could also use MAX()
FROM
    tableX
GROUP BY
    user_id ;

MySQL permet également la solution peu orthodoxe suivante, qui renverra un commentaire (plus ou moins aléatoire) par utilisateur:

SELECT
    user_id
  , comment
FROM
    tableX
GROUP BY
    user_id ;

Cette dernière requête ne fonctionnera pas mais générera une erreur si le ONLY_FULL_GROUP_BYmode (plus strict) est activé. Dans la version 5.7 récemment publiée, ce mode est le mode par défaut et une nouvelle fonction ANY_VALUE()est fournie. Pour plus de détails, voir la page MySQL HandlingGROUP BY . La requête peut être écrite maintenant:

SELECT
    user_id
  , ANY_VALUE(comment) AS comment
FROM
    tableX
GROUP BY
    user_id ;

Notez qu'avec la version "peu orthodoxe" ou en utilisant la ANY_VALUE()fonction récente , si nous ajoutons plus de colonnes dans la SELECTliste, leurs valeurs ne sont pas garanties d'être de la même ligne, juste d'une ligne du même groupe. La façon dont ils sont sélectionnés n'est pas exactement aléatoire, dépend du plan d'exécution et des index utilisés.

ypercubeᵀᴹ
la source
Existe-t-il d'autres façons de spécifier la ligne à extraire pour un ID utilisateur? Est-il possible de spécifier un type de COMMANDE PAR?
Jake Wilson
D'ailleurs MINet MAX?
ypercubeᵀᴹ
1
C'est alors plus complexe. Voir cette autre question: MySQL Query - Comment obtenir les données démographiques les plus récentes?
ypercubeᵀᴹ
2
Vous trouverez également une tonne de problèmes similaires dans le site SO, sous la [greatest-n-per-group]balise.
ypercubeᵀᴹ
1
@ T.BrianJones voulez-vous dire dans la requête "peu orthodoxe", si vous ajoutez toutes les autres colonnes dans la liste SELECT? C'est le premier, ils peuvent ne pas appartenir à la même rangée. Ce n'est pas exactement aléatoire, mais les valeurs peuvent provenir de différentes lignes (du même groupe).
ypercubeᵀᴹ