Pourquoi cela ne fonctionne pas avec GROUP BY
SELECT *
ne peut pas être utilisé avec GROUP BY
; c'est du SQL invalide. GROUP BY
ne sélectionne pas les lignes du tableau. Il crée des groupes de lignes en utilisant les expressions fournies puis, à partir de chaque groupe, il génère un nouvel enregistrement et calcule chaque colonne de ce nouvel enregistrement en utilisant les valeurs impliquées dans l'expression.
Les colonnes qui apparaissent dans le SELECT
la clause doit satisfaire l'une des règles suivantes :
- apparaissent également dans le
GROUP BY
clause ; - sont utilisés avec
GROUP BY
fonctions d'agrégation ; - sont fonctionnellement dépendantes des colonnes qui apparaissent dans le
GROUP BY
clause.
Tant que *
est un raccourci pour tous les noms de colonnes de la ou des tables utilisées par la requête, pour votre requête uniquement le user
colonne satisfont à l'une des exigences ci-dessus.
Avant la version 5.7.5
MySQL n'a pas implémenté la troisième règle ci-dessus. Il acceptait les requêtes qui contiennent dans le SELECT
les colonnes de clause qui ne suivent aucun des GROUP BY
conditions. La valeur renvoyée par la requête pour ces colonnes était indeterminate
.
Depuis la version 5.7.5, MySQL rejette le GROUP BY
requêtes qui satisfont aux exigences.
La solution
Dans tous les cas, la solution à votre problème n'implique pas GROUP BY
. Cela peut être facilement accompli en utilisant un LEFT JOIN
avec les bonnes conditions :
SELECT lc.*
FROM comments lc # 'lc' from 'last comment'
LEFT JOIN comments nc # 'nc' from 'newer comment'
ON lc.user = nc.user # both comments belong to the same user
AND lc.id < nc.id # 'nc' is newer than 'lc'
WHERE nc.id IS NULL # there is no 'newer comment'
ORDER BY lc.id DESC
LIMIT 10
Comment ça marche
Il rejoint la table comments
, alias lc
("lc" du "dernier commentaire" d'un utilisateur) contre lui-même, alias nc
("nc" de "commentaire plus récent"). La clause join correspond à chaque entrée de lc
avec toutes les entrées de nc
qui appartiennent au même utilisateur (lc.user = nc.user
) et sont plus récents (lc.id < nc.id
; J'ai supposé que les identifiants sont attribués de manière séquentielle et que les commentaires les plus récents ont des valeurs plus élevées pour id
).
L'utilisation de LEFT JOIN
garantit que chaque ligne de lc
apparaît dans le résultat de la jointure, même lorsqu'aucune ligne correspondante n'est trouvée dans nc
(parce qu'il n'y a pas de commentaire plus récent du même utilisateur). Dans ce cas, NULL
est utilisé à la place des champs de nc
. Le WHERE
La clause conserve dans le jeu de résultats final uniquement les lignes qui ont NULL
dans nc.id
; cela signifie dans le lc
partie ils contiennent le commentaire le plus récent de chaque utilisateur.
Le SELECT
la clause contient tous les champs de lc
(ceux de nc
sont tous NULL
, De toute façon). Le ORDER BY
La clause peut être utilisée pour trier le jeu de résultats. ORDER BY lc.id DESC
place les commentaires les plus récents en premier et le LIMIT
clause conserve le jeu de résultats à une taille décente.