Order Select Based on Join Results (Sort Conversations on Last Message Sent)

后端 未结 1 1948
Happy的楠姐
Happy的楠姐 2021-01-28 13:31

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

1条回答
  •  后悔当初
    2021-01-28 14:02

    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.

    0 讨论(0)
提交回复
热议问题