2009-10-08 16 views
7

Ho una tabella come questa:MySQL Raggruppa con un numero superiore N di ogni tipo

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

e ho bisogno la parte superiore 2 di ogni lettera in ordine di rango ascendente:

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

Come sarebbe Lo faccio? E 'abbastanza semplice per ottenere solo la parte superiore 1 utilizzando GROUP BY, ma io non riesco a farlo funzionare per più voci

risposta

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: (il mio primo tentativo non funziona su MySql (Quassnoi commenti), ho modificato per lavorare sul server di SQL per esempio)

secondo tentativo:

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

Il predicato 'IN' non funziona con' LIMIT' in 'MySQL' – Quassnoi

+0

scusa, lavoro di più con SQL Server. Ora devo trovare un'altra soluzione per mysql e diversa dalla tua;) – 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 
       ) 

È necessario disporre di un indice composito sulla (Letter, Rank) (in questo ordine)

Nota questo costrutto:

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

invece di mera md.Letter = mo.Letter

forza Range checked for each record che è più ef ciente.

si veda questo articolo nel mio blog:

per maggiori dettagli su questo.

+0

I' m ricevendo un errore di "# 1242 - Subquery restituisce più di 1 riga" a causa del LIMIT 2 sull'ultima sottoquery, sai perché potrebbe essere? – Rik

+0

'LIMITE' errato, risolto. – Quassnoi

+0

Questa è una vecchia risposta, ma l'ho trovata utile. Tuttavia, ho trovato che non funziona come previsto. Se ci sono meno di 2 istanze di una lettera, ad esempio, non ne restituirà nessuna. È possibile aggiungere qualcosa di simile: OR ( SELECT COUNT (*) FROM tabella mi DOVE mi.letter = mo.letter ) <= 2) ; –

Problemi correlati