Mysql
 sql >> Base de données >  >> RDS >> Mysql

afficher le dernier commentaire qui ne contient qu'un seul commentaire par utilisateur

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.