web-dev-qa-db-fra.com

Comment obtenir le dernier enregistrement dans chaque groupe en utilisant GROUP BY?

Disons que j'ai une table appelée messages avec les colonnes:

id | from_id | to_id | subject | message | timestamp

Je souhaite obtenir le dernier message de chaque utilisateur uniquement, comme vous le verriez dans votre boîte de réception FaceBook avant d'explorer le fil de discussion.

Cette requête semble me rapprocher du résultat dont j'ai besoin:

SELECT * FROM messages GROUP BY from_id

Cependant, la requête me donne le message le plus ancien de chaque utilisateur et non le plus récent.

Je ne peux pas comprendre celui-ci.

38
user1019144

Vous devez trouver les dernières valeurs de timestamp dans chaque groupe (sous-requête), puis joindre cette sous-requête à la table -

SELECT t1.* FROM messages t1
  JOIN (SELECT from_id, MAX(timestamp) timestamp FROM messages GROUP BY from_id) t2
    ON t1.from_id = t2.from_id AND t1.timestamp = t2.timestamp;
82
Devart

Essaye ça

SELECT * FROM messages where id in (SELECT max(id) FROM messages GROUP BY from_id ) order by id desc
18
Venu M

cette requête renvoie le dernier enregistrement pour chaque Form_id:

    SELECT m1.*
     FROM messages m1 LEFT JOIN messages m2
     ON (m1.Form_id = m2.Form_id AND m1.id < m2.id)
     WHERE m2.id IS NULL;
3
leyla azari

Il s'agit d'un problème standard.

Notez que MySQL vous permet d'omettre des colonnes de la clause GROUP BY, ce que Standard SQL ne fait pas, mais vous n'obtenez pas de résultats déterministes en général lorsque vous utilisez la fonction MySQL.

SELECT *
  FROM Messages AS M
  JOIN (SELECT To_ID, From_ID, MAX(TimeStamp) AS Most_Recent
          FROM Messages
         WHERE To_ID = 12345678
         GROUP BY From_ID
       ) AS R
    ON R.To_ID = M.To_ID AND R.From_ID = M.From_ID AND R.Most_Recent = M.TimeStamp
 WHERE M.To_ID = 12345678

J'ai ajouté un filtre sur le To_ID pour correspondre à ce que vous êtes susceptible d'avoir. La requête fonctionnera sans elle, mais renverra beaucoup plus de données en général. La condition ne doit pas nécessairement être indiquée à la fois dans la requête imbriquée et dans la requête externe (l'optimiseur doit pousser la condition automatiquement), mais il ne peut pas nuire à répéter la condition comme indiqué.

1
Jonathan Leffler

Complétant simplement ce que Devart a dit, le code ci-dessous ne commande pas selon la question:

SELECT t1.* FROM messages t1
  JOIN (SELECT from_id, MAX(timestamp) timestamp FROM messages GROUP BY from_id) t2
    ON t1.from_id = t2.from_id AND t1.timestamp = t2.timestamp;

La clause "GROUP BY" doit être dans la requête principale car nous devons d'abord réorganiser la "SOURCE" pour obtenir le "groupement" nécessaire:

SELECT t1.* FROM messages t1
  JOIN (SELECT from_id, MAX(timestamp) timestamp FROM messages ORDER BY timestamp DESC) t2
    ON t1.from_id = t2.from_id AND t1.timestamp = t2.timestamp GROUP BY t2.timestamp;

Cordialement,

1
Bruno de Oliveira