O problema é devido a uma extensão específica do MySQL para o comportamento do
GROUP BY
cláusula. Outros bancos de dados lançariam um erro... algo parecido com on-aggregate na lista SELECT". (Podemos fazer o MySQL lançar um erro semelhante, se incluirmos ONLY_FULL_GROUP_BY em sql_mode.) O problema com a expressão
messages.created
é que se refere a um valor de uma linha indeterminada no GROUP BY. A operação ORDER BY ocorre muito mais tarde no processamento, após a operação GROUP BY. Para obter o "último" criado para cada grupo, use um agregado expressão
MAX(messages.created)
. Para obter os outros valores dessa mesma linha, é um pouco mais complicado.
Supondo que
created
é único dentro de um determinado conversation_id
group (ou, se não houver garantia de que não é exclusivo, e você não tem problema em retornar várias linhas com o mesmo valor para created
... Para obter o último
created
para cada 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
Você pode usar isso como uma visualização inline, para obter a linha inteira com o último
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)
NOTAS:
Você pode adicionar um
ORDER BY
cláusula para ordenar as linhas retornadas da maneira que você precisar. O
WHERE
cláusula na consulta externa é provavelmente redundante e desnecessária. Preferimos evitar o uso de
SELECT *
, e prefira listar explicitamente as expressões a serem retornadas.