45 votes

Commande de groupe par MySQL

J'ai le tableau suivant :

    id       time      text      otheridentifier
    -------------------------------------------
    1        6         apple     4
    2        7         orange    4
    3        8         banana    3
    4        9         pear      3
    5        10        grape     2

Ce que je veux faire est de sélectionner les 3 enregistrements les plus récents (par ordre chronologique), dont otheridentifier sont distincts. Donc, dans ce cas, le résultat serait id 's : 5, 4, et 2.

id = 3 serait ignoré parce qu'il y a un enregistrement plus récent avec la même otheridentifier champ.

Voici ce que j'ai essayé de faire :

SELECT * FROM `table` GROUP BY (`otheridentifier`) ORDER BY `time` DESC LIMIT 3

Cependant, je finis par obtenir des rangées de id = 5, 3 et 1 au lieu de 5, 4, 2 comme prévu.

Quelqu'un peut-il me dire pourquoi cette requête ne renvoie pas ce que j'attendais ? J'ai essayé de changer le ORDER BY en ASC mais cela ne fait que réorganiser les lignes retournées en 1, 3, 5.

Merci pour votre aide !

34voto

chaos Points 69029

Il ne renvoie pas ce que vous attendez parce que le regroupement a lieu avant l'ordonnancement, comme le reflète la position des clauses dans l'instruction SQL. Vous allez malheureusement devoir faire preuve d'imagination pour obtenir les lignes que vous voulez. Essayez ceci :

SELECT *
FROM `table`
WHERE `id` = (
    SELECT `id`
    FROM `table` as `alt`
    WHERE `alt`.`otheridentifier` = `table`.`otheridentifier`
    ORDER BY `time` DESC
    LIMIT 1
)
ORDER BY `time` DESC
LIMIT 3

18voto

Andomar Points 115404

Vous pourriez joindre la table sur elle-même pour filtrer la dernière entrée par otheridentifier puis prenez les trois premières lignes :

SELECT last.*
FROM `table` last
LEFT JOIN `table` prev 
    ON prev.`otheridentifier` = last.`otheridentifier`
    AND prev.`time` < last.`time`
WHERE prev.`id` is null
ORDER BY last.`time` DESC 
LIMIT 3

4voto

11101101b Points 3343

J'avais une exigence similaire, mais j'avais des critères de sélection plus avancés. En utilisant certaines des autres réponses, je n'ai pas pu obtenir exactement ce dont j'avais besoin, mais j'ai découvert que vous pouvez toujours faire un GROUP BY après un ORDER BY comme ceci :

SELECT t.* FROM (SELECT * FROM table ORDER BY time DESC) t 
GROUP BY t.otheridentifier

2voto

Rytmis Points 15848
SELECT * FROM table t1 
WHERE t1.time = 
    (SELECT MAX(time) FROM table t2 
     WHERE t2.otheridentifier = t1.otheridentifier)

2voto

bernie Points 44206

Réponse d'Andomar est probablement la meilleure, car elle n'utilise pas de sous-requête.

Une approche alternative :

select *
from   `table` t1
where  t1.`time` in (
                    select   max(s2.`time`)
                    from     `table` t2
                    group by t2.otheridentifier
                    )

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X