sql >> Database >  >> RDS >> Mysql

Bestelling selecteren op basis van deelnameresultaten (Gesprekken sorteren op laatst verzonden bericht)

Het probleem is te wijten aan een MySQL-specifieke uitbreiding van het gedrag van de GROUP BY clausule. Andere databases zouden een fout geven... iets dat lijkt op on-aggregate in SELECT list". (We kunnen MySQL een soortgelijke fout laten genereren, als we ONLY_FULL_GROUP_BY opnemen in sql_mode.)

Het probleem met de uitdrukking messages.created is dat verwijst naar een waarde uit een onbepaalde rij in de GROUP BY. De ORDER BY-bewerking vindt veel later in de verwerking plaats, na de GROUP BY-bewerking.

Gebruik een aggregaat . om het "nieuwste" voor elke groep te krijgen uitdrukking MAX(messages.created) .

Het is iets ingewikkelder om de andere waarden uit dezelfde rij te halen.

Ervan uitgaande dat created is uniek binnen een gegeven conversation_id groep (of, als er geen garantie is dat het niet uniek is, en je bent akkoord met het retourneren van meerdere rijen met dezelfde waarde voor created ...

Om de nieuwste created te krijgen voor elke 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

Je kunt dat gebruiken als een inline-weergave om de hele rij te krijgen met die laatste 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)

OPMERKINGEN:

U kunt een ORDER BY . toevoegen clausule om de geretourneerde rijen te ordenen zoals u dat wilt.

De WHERE clausule op de buitenste query is waarschijnlijk overbodig en onnodig.

We vermijden liever het gebruik van SELECT * , en geven er de voorkeur aan expliciet de expressies te vermelden die moeten worden geretourneerd.




  1. Kan geen verbinding maken met database:toegang geweigerd voor gebruiker ''@'localhost' tot database 'socialdb'

  2. PreparedStatement en setTimestamp in oracle jdbc

  3. Re-Slaven van een gecrashte MySQL-masterserver in semisynchrone replicatieconfiguratie

  4. Een tabel maken met een rekenkundige overloopfout