2009-10-08 3 views
7

У меня есть таблица вроде этого:MySQL Group By с верхним N числа каждого вида

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

И мне нужно верхнюю 2 каждой буквы заказанного восходящим ранга:

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

Как Я делаю это? Это довольно просто, чтобы получить только верхний 1 с помощью GROUP BY, но я, кажется, не могу получить его работу для нескольких записей

ответ

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: (моя первая попытка не будет работать на MySql (Quassnoi комментарий), я изменил его на работу на сервере SQL, например)

вторая попытка:

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' предикат не работает с' LIMIT' в 'MySQL' – Quassnoi

+0

извините, я больше работаю с сервером sql. Теперь я должен найти другое решение для mysql и отличается от вашего;) – 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 
       ) 

Вы должны иметь составной индекс по (Letter, Rank) (в таком порядке)

Примечание эта конструкция:

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

вместо простого md.Letter = mo.Letter

это заставляет Range checked for each record которое более эфф ficient.

Смотрите эту статью в своем блоге:

для получения более подробной информации по этому вопросу.

+0

Я m получить ошибку «# 1242 - Subquery возвращает более 1 строки» из-за LIMIT 2 в последнем подзапросе, знаете ли вы, почему это может быть? – Rik

+0

Неправильный 'LIMIT', исправленный. – Quassnoi

+0

Это старый ответ, но я нашел его полезным. Однако я обнаружил, что он работает не так, как ожидалось. Если есть менее двух экземпляров письма, например, оно не будет возвращать ни одно из них. Вы можете добавить что-то вроде этого: ИЛИ ( SELECT COUNT (*) FROM туЬаОго ми WHERE mi.letter = mo.letter ) <= 2) ; –