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.