2009-10-08 8 views
7

J'ai une table comme ceci:Groupe MySQL par numéro top N de chaque type

 
Rank  Letter 
1   A 
2   A 
3   B 
4   A 
5   C 
6   A 
7   C 
8   C 
9   B 
10  C 

Et je dois le top 2 de chaque lettre ordonnée par ordre croissant:

 
Rank  Letter 
1   A 
2   A 
3   B 
5   C 
7   C 
9   B 

Comment se Je le fais? Il est assez facile d'obtenir juste le top 1 en utilisant GROUP BY, mais je ne peux pas sembler le faire fonctionner pour plusieurs entrées

Répondre

2
select distinct rank, letter 
    from table1 t2 
where rank in 
     (select top 2 rank 
      from table1 t2 
      where t2.letter = t1.letter 
      order by rank) 
     order by letter, rank 

EDIT: (mon premier essai ne fonctionne pas sur MySql (de commentaire Quassnoi), je l'ai modifié pour fonctionner sur le serveur SQL par exemple)

deuxième essai:

select t.letter, t.rank 
from table1 t 
join (
    select t1.letter, min(t1.rank) m 
    from table1 t1 
    join (select t0.letter, min(t0.rank) m, count(1) c 
      from table1 t0 group by t0.letter) t2 
    on t1.letter = t2.letter and ((t2.c = 1) or (t2.c > 1 and t1.rank > m)) 
    group by t1.letter) t3 
    on t.letter = t3.letter and t.rank <= t3.m 
+0

'IN' prédicat ne fonctionne pas avec' LIMIT' dans 'MySQL' – Quassnoi

+0

désolé, je travaille plus avec SQL Server. Maintenant, je dois trouver une autre solution pour mysql et différente de la vôtre;) – manji

7
SELECT mo.Letter, md.Rank 
FROM (
     SELECT DISTINCT letter 
     FROM mytable 
     ) mo 
JOIN mytable md 
ON  md.Letter >= mo.Letter 
     AND md.Letter <= mo.Letter 
     AND Rank <= 
     COALESCE 
       (
       (
       SELECT Rank 
       FROM mytable mi 
       WHERE mi.letter = mo.letter 
       ORDER BY 
         Rank 
       LIMIT 1, 1 
       ), 
       0xFFFFFFFF 
       ) 

Vous devez avoir un indice composite sur (Letter, Rank) (dans cet ordre)

Notez cette construction:

md.Letter >= mo.Letter 
AND md.Letter <= mo.Letter 

au lieu de la simple md.Letter = mo.Letter

Il force Range checked for each record qui est plus ef ficient.

Voir cet article dans mon blog:

pour plus de détails à ce sujet.

+0

Je m obtenant une erreur de "# 1242 - Sous-requête retourne plus de 1 ligne" en raison de la limite 2 sur la dernière sous-requête, savez-vous pourquoi cela pourrait être? – Rik

+0

Mauvais 'LIMIT', fixe. – Quassnoi

+0

Ceci est une vieille réponse, mais je l'ai trouvé utile. J'ai cependant trouvé que cela ne fonctionne pas comme prévu. S'il y a moins de deux instances d'une lettre, par exemple, il n'en renverra aucune. Vous pouvez ajouter quelque chose comme ceci: OU ( SELECT COUNT (*) FROM mytable mi Où mi.letter = mo.letter ) <= 2) ; –

Questions connexes