I am creating an SQL query in Hibernate for a messaging component. The idea is that I am querying to get conversations for a user, sorted on the date of the las
The issue is due to a MySQL-specific extension to the behavior of the GROUP BY
clause. Other databases would throw an error... something akin to on-aggregate in SELECT list". (We can get MySQL to throw a similar error, if we include ONLY_FULL_GROUP_BY in sql_mode.)
The issue with the expression messages.created
is that refers to a value from an indeterminate row in the GROUP BY. The ORDER BY operation occurs much later in the processing, after the GROUP BY operation.
To get the "latest" created for each group, use an aggregate expression MAX(messages.created)
.
To get the other values from that same row, is a little more complicated.
Assuming that created
is unique within a given conversation_id
group (or, if there's no guaranteed that it's not unique, and you are okay with returning multiple rows with the same value for created
...
To get the latest created
for each 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
You can use that as an inline view, to get the whole row with that latest 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)
NOTES:
You can add an ORDER BY
clause to order the rows returned however you need.
The WHERE
clause on the outer query is likely redundant, and unnecessary.
We prefer to avoid using SELECT *
, and prefer to explicitly list the expressions to be returned.