2009-08-20 11 views
5

Jetez un oeil à la table MySQL ci-dessous appelé « Articles »:trouver la ligne avec une valeur maximale de id dans MySQL

+----+-----------+---------+------------------------+--------------------------+ 
| id | articleId | version | title     | content     | 
+----+-----------+---------+------------------------+--------------------------+ 
| 1 |   1 | 0.0  | ArticleNo.1 title v0.0 | ArticleNo.1 content v0.0 | 
| 2 |   1 | 1.0  | ArticleNo.1 title v1.0 | ArticleNo.1 content v1.0 | 
| 3 |   1 | 1.5  | ArticleNo.1 title v1.5 | ArticleNo.1 content v1.5 | 
| 4 |   1 | 2.0  | ArticleNo.1 title v2.0 | ArticleNo.1 content v2.0 | 
| 5 |   2 | 1.0  | ArticleNo.2 title v1.0 | ArticleNo.2 content v1.0 | 
| 6 |   2 | 2.0  | ArticleNo.2 title v2.0 | ArticleNo.2 content v2.0 | 
+----+-----------+---------+------------------------+--------------------------+ 

Im essayant de trouver une requête pour retourner Articles.id où Articles.version est le nombre maximum.

La table Articles réelle contient plus de 10 000 entrées.

Donc, dans cet exemple, je veux seulement que les articles .id 4 et 6 soient retournés. J'ai regardé le mot-clé distinct et la fonction max() mais ne peux pas sembler le clouer.

Toutes les suggestions ... appréciées

Répondre

4

Vous avez besoin d'une sous requête ici:

SELECT a.id, a.version 
FROM articles a 
WHERE a.version = (
    SELECT MAX(version) 
    FROM articles b 
    WHERE b.articleId = a.articleId 
) 
+0

Ceci renvoie uniquement les dernières versions des articles, en supprimant les versions précédentes/antérieures. Belles requêtes les gars, merci beaucoup! –

+0

Juste pour le compte rendu: T.J. Crowder a souligné dans sa réponse qu'une sous-requête n'est pas obligatoire: elle peut aussi être faite avec un LEFT JOIN. – soulmerge

4

Vous pouvez utiliser un sous-requête ici:

select 
    a.id 
from 
    articles a 
where 
    a.version = (select max(version) from articles) 

Puisque ce n'est pas une sous-requête corrélée, il sera assez rapide (aussi vite ou plus vite que une jointure), vous n'avez donc pas besoin de vous inquiéter à ce sujet. Mais il renverra toutes les valeurs qui ont le maximum articleid.

Bien sûr, je vous recommande de lancer un index sur articleid (en supposant que id est déjà en cluster). Cela l'aidera à revenir encore plus vite.

Comme il est indiqué dans les commentaires, si vous voulez obtenir la version max pour chaque articleid, vous pouvez effectuer les opérations suivantes:

select 
    a.id 
from 
    articles a 
    inner join (select articleid, max(version) 
       from articles group by articleid) as b on 
     a.articleid = b.articleid 
     and a.version = b.version 

Cela va créer une jointure de cette sous-requête et généralement beaucoup plus rapide que une sous-requête corrélée qui sélectionne le maximum pour chaque articleid.

+1

Ce n'est pas correct - ceci sélectionne l'ID d'article maximum est max, pas la version d'article. – tw39124

+0

@Tom: Oui, et maintenant je l'ai réparé, donc c'est juste. – Eric

+0

Notez que ceci sélectionnera seulement les articles qui ont la * même * version. Si vous voulez récupérer la dernière version de * chaque * article, jetez un oeil à ma réponse ci-dessous. – soulmerge

1

SELECT Articles.id FROM Articles WHERE Articles.version IN (SELECT MAX(Articles.version) FROM Articles)

1

peut-être quelque chose comme:

select * from articles où articleid dans (select max (articleversion) à partir des articles)

1

Vous pouvez faire

SELECT articles.id 
    FROM articles a 
WHERE NOT EXISTS(SELECT * FROM articles a2 WHERE a2.version > a.version) 

Je ne Je sais que MySQL fonctionnera avec lui, mais Oracle et SQL Server lui conviennent parfaitement.

5

De l'MySQL manual, cela ne l'astuce:

SELECT a1.id 
FROM Articles a1 
LEFT JOIN Articles a2 ON a1.articleId = a2.articleId AND a1.version < a2.version 
WHERE a2.articleId IS NULL; 

Voir le lien pour raison d'être.

+0

Sachez également que les sous-requêtes de la clause WHERE dans MySQL peuvent être exécutées pour chaque ligne du résultat, c'est donc probablement la réponse la plus performante. –

1

Toutes les réponses ci-dessus peuvent résoudre le problème déclaré de DJDonaL3000. Mais, la plupart d'entre eux sont des sous-requêtes corrélées qui entravent la performance de l'application. Si vous utilisez une application cloud, je vous suggère de ne pas utiliser les requêtes ci-dessus. Le meilleur moyen est alors de maintenir deux tables, A et B. A contenant toujours la dernière version de l'article et B ayant des détails sur toutes les versions. Le problème est qu'il y aura plus de mises à jour et d'insertions dans les tables, mais l'extraction sera plus rapide car il vous suffit d'exécuter une requête de sélection normale dans la table A.Faire un groupe par et max dans une requête interne vous coûtera