2010-04-07 5 views
9

Je dois sélectionner les deux derniers enregistrements pour chaque sujet.Comment sélectionner les deux derniers enregistrements pour chaque topic_id dans MySQL

ex: table: msg

id | topic_id 
------------ 
1 | 1 
2 | 1 
3 | 1 
4 | 1 
5 | 2 
6 | 2 
7 | 2 
8 | 3 
9 | 3 
10 | 3 

Je veux obtenir ces lignes:

3 1 
4 1 
6 2 
7 2 
9 3 
10 3 

Comment puis-je faire cela?

grâce

+0

Y a-t-il des raccourcis que nous pourrions supposer? par exemple, dans les données ci-dessus vos identifiants sont ascendants sans trous et pour les identifiants ascendants, vous avez aussi un topic_id croissant - si nous pouvons supposer que cela rendra la requête plus facile. une autre approche pourrait utiliser l'hypothèse qu'il y a au moins deux entrées pour chaque topic_id. pouvons-nous supposer cela? – Unreason

Répondre

1

Vous pourriez

SELECT a.id, a.topic_id 
FROM MSG a 
WHERE a.id IN (
    SELECT t.id 
    FROM MSG t 
    WHERE a.topic_id = t.topic_id 
    ORDER BY t.id DESC 
    LIMIT 2) 
ORDER BY a.topic_id, a.id 

EDIT: Comme il semble que MySQL ne permet pas (! Mais il sera possible dans les versions ultérieures) à utiliser LIMIT dans les sous-requêtes ici est une solution généralisée (sans hypothèses de raccourci, sauf que msg.id est unique par topic_id):

SELECT a.id, a.topic_id 
FROM MSG a 
WHERE a.id IN (
    SELECT MAX(t.id) 
    FROM MSG t 
    WHERE a.topic_id = t.topic_id 
      ) OR 
     a.id IN (
    SELECT MAX(t.id) 
    FROM MSG t 
    WHERE a.topic_id = t.topic_id AND 
    t.id NOT IN (
     SELECT MAX(t2.id) 
     FROM MSG t2 
     WHERE t.topic_id = t2.topic_id 
       ) 
      )  
ORDER BY a.topic_id, a.id 

bien sûr, ce n'est pas agréable, mais vous y êtes. Si l'on suppose que les ids dans topic_id sont ascendants sans trous, d'autres améliorations peuvent être apportées à la requête.

+0

il me donne l'erreur suivante "MySQL ne supporte pas encore 'LIMIT & IN/ALL/ANY/QUELQUES sous-requêtes'" – Salil

+0

réponse mis à jour pour compenser la limitation mysql que je n'étais pas au courant. – Unreason

0

Je voudrais savoir une meilleure réponse pour cela mais la requête suivante fonctionnera.

SELECT * FROM msg where id in (SELECT m.id FROM msg m group by topic_id) 
      or id in (SELECT m1.id FROM msg m1 where id not in (SELECT m2.id FROM msg m2 roup by topic_id) 
group by topic_id) order by id 
+0

en fait ce n'est pas le cas (il manque une faute dans la deuxième sous-requête, cherchez roup) mais surtout - mysql ne garantit pas que la valeur des colonnes non incluses dans le groupe provient du dernier enregistrement. (ou en d'autres termes, si votre requête renvoie les résultats souhaités, alors par définition c'est seulement par coïncidence et elle peut cesser de fonctionner à un moment donné) – Unreason

3

Un travail autour de SQL ne prenant pas en charge la limite suivie de la clause IN est simple. Construisez simplement une autre sous-requête dans votre clause IN. Donc par exemple.

SELECT a.id, a.topic_id 
FROM MSG a 
WHERE a.id IN (
    SELECT t.id 
    FROM (Select * from MSG t 
    WHERE a.topic_id = t.topic_id 
    ORDER BY t.id DESC 
    LIMIT 2)alias) 
ORDER BY a.topic_id, a.id 

Faites-moi savoir comment cela fonctionne pour vous.

+0

Avec cette requête, j'obtiens l'erreur "Colonne inconnue 'a.topic_id' dans ' où clause '" – rayne

3
SELECT max(id), max(topic_id) FROM msg 
GROUP BY topic_id 

UNION 

SELECT max(id), max(topic_id) FROM msg 
WHERE id not in (
    SELECT max(id) as id FROM msg 
    GROUP BY topic_id) 
GROUP BY topic_id 
Questions connexes