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

Trier la sélection en fonction des résultats de la jointure (trier les conversations sur le dernier message envoyé)

Le problème est dû à une extension spécifique à MySQL du comportement de GROUP BY clause. D'autres bases de données généreraient une erreur... quelque chose qui s'apparente à un agrégat dans la liste SELECT". (Nous pouvons demander à MySQL de générer une erreur similaire, si nous incluons ONLY_FULL_GROUP_BY dans sql_mode.)

Le problème avec l'expression messages.created est qui fait référence à une valeur d'une ligne indéterminée dans GROUP BY. L'opération ORDER BY intervient beaucoup plus tard dans le traitement, après l'opération GROUP BY.

Pour obtenir le "dernier" créé pour chaque groupe, utilisez un agrégat expression MAX(messages.created) .

Pour obtenir les autres valeurs de cette même ligne, c'est un peu plus compliqué.

En supposant que created est unique dans un conversation_id donné groupe (ou, s'il n'y a aucune garantie qu'il n'est pas unique, et que vous êtes d'accord pour renvoyer plusieurs lignes avec la même valeur pour created ...

Pour obtenir le dernier created pour chaque conversation_id

SELECT lm.conversation_id
     , MAX(lm.created) AS created
  FROM conversation lc
  JOIN message lm
    ON lm.conversation_id = lc.id
 WHERE (lc.creator_id = :userId OR lc.to_id = :userId)
 GROUP BY lm.conversation_id

Vous pouvez l'utiliser comme une vue en ligne, pour obtenir la ligne entière avec ce dernier created

SELECT c.*
     , m.*
  FROM ( SELECT lm.conversation_id
              , MAX(lm.created) AS created
           FROM conversation lc
           JOIN message lm
             ON lm.conversation_id = lc.id
          WHERE (lc.creator_id = :userId OR lc.to_id = :userId)
          GROUP BY lm.conversation_id
       ) l
  JOIN conversation c
    ON c.id = l.conversation_id
  JOIN messages m
    ON m.conversation_id = l.conversation_id
   AND m.created         = l.created
 WHERE (c.creator_id = :userId OR c.to_id = :userId)

REMARQUES :

Vous pouvez ajouter un ORDER BY clause pour trier les lignes renvoyées selon vos besoins.

Le WHERE clause sur la requête externe est probablement redondante et inutile.

Nous préférons éviter d'utiliser SELECT * , et préférez lister explicitement les expressions à renvoyer.