2013-04-12 12 views
12

Mam tabeli w następujący sposób:W SQL, jak wybrać Top 2 wiersze dla każdej grupy

NAME SCORE 
----------------- 
willy  1 
willy  2 
willy  3 
zoe   4 
zoe   5 
zoe   6 

Oto sample

Funkcja agregacja dla group by tylko pozwala mi, aby uzyskać najwyższy wynik dla każdego name. Chciałbym zapytać, aby uzyskać najwyższy wynik 2 dla każdego name, jak mam to zrobić?

Moja oczekiwana produkcja jest

NAME SCORE 
----------------- 
willy  2 
willy  3 
zoe   5 
zoe   6 

Odpowiedz

19
SELECT * 
FROM test s 
WHERE 
     (
      SELECT COUNT(*) 
      FROM test f 
      WHERE f.name = s.name AND 
        f.score >= s.score 
     ) <= 2 
+1

ale które mogą powodować problemy z wydajnością. czy istnieje jakaś szybsza metoda realizacji tego zapytania? –

+0

To rzeczywiście powoduje bardzo duże problemy z wydajnością (podselekcja jest kwadratowa). –

+0

Można to zrobić liniowo, zobacz "Zapytanie MySQL do Top 2" tutaj http://www.sqlines.com/mysql/how-to/get_top_n_each_group – mdubez

0

Do tego można zrobić this-

http://www.sqlfiddle.com/#!2/ee665/4

, ale aby uzyskać pierwsze 2 zapytanie, należy użyć identyfikatora, a następnie uruchomić limit dla identyfikatora takiego jak 0,2.

+0

Obawiam się, że to nie jest to, czego się spodziewam – waitingkuo

+0

tak, ja tylko byłem podając metodę, możesz to zrobić w prosty sposób, jeśli posiadasz identyfikator dla każdego wiersza (klucz podstawowy), to będzie działać więcej i będziesz miał więcej funkcji w zasięgu ręki. W ten sposób potrzebujesz długiego kodu, a także, że w przyszłości będzie ci trudniej używać cokolwiek innego. – devilcrab

9

W MySQL można używać zmiennych zdefiniowanych przez użytkownika, aby uzyskać liczbę wierszy w każdej grupie:

select name, score 
from 
(
    SELECT name, 
    score, 
    (@row:=if(@prev=name, @row +1, if(@prev:= name, 1, 1))) rn 
    FROM test123 t 
    CROSS JOIN (select @row:=0, @prev:=null) c 
    order by name, score desc 
) src 
where rn <= 2 
order by name, score; 

Zobacz Demo

+0

Dziękuję za to rozwiązanie, wciąż jestem nowy w SQL. Mam nadzieję, że mogę to zrozumieć w przyszłości :) – waitingkuo

+0

@waitingkuo Niestety MySQL nie ma funkcji okienkowania, które pozwoliłyby z łatwością przypisać numer wiersza do każdego wiersza w grupie. – Taryn

+0

@bluefeet dziękuje, że jest to bardzo dobre rozwiązanie, działało bardzo szybko, nawet na 30 tys. Wierszy, moje wcześniejsze rozwiązanie z wykorzystaniem złączeń było bardzo powolne. – asm234

0

Można zrobić somthething tak:

SET @num :=0, @name :=''; 
SELECT name, score, 
    @num := IF(@name= name, @num +1, 1) AS row_number, 
    @name := name AS dummy 
FROM test 
GROUP BY name, score 
HAVING row_number <=2 
2

Jeśli nie masz nic przeciwko posiadaniu dodatkowej kolumny, możesz użyć następującego kodu:

SELECT Name, Score, rank() over(partition by Name, order by Score DESC) as rank 
From Table 
Having rank < 3; 

Rank funkcja zapewnia rangę dla każdej partycji, w Twoim przypadku jest to nazwa

0
SELECT * FROM ( 
    SELECT VD.`cat_id` , 
     @cat_count := IF((@cat_id = VD.`cat_id`), @cat_count + 1, 1) AS 'DUMMY1', 
     @cat_id := VD.`cat_id` AS 'DUMMY2', 
     @cat_count AS 'CAT_COUNT' 
    FROM videos VD 
    INNER JOIN categories CT ON CT.`cat_id` = VD.`cat_id` 
     ,(SELECT @cat_count :=1, @cat_id :=-1) AS CID 
    ORDER BY VD.`cat_id` ASC) AS `CAT_DETAILS` 
    WHERE `CAT_COUNT` < 4 

------- STEP FOLLOW ---------- 
1 . select * from ('FILTER_DATA_HERE') WHERE 'COLUMN_COUNT_CONDITION_HERE' 
2. 'FILTER_DATA_HERE' 
    1. pass 2 variable @cat_count=1 and @cat_id = -1 
    2. If (@cat_id "match" column_cat_id value) 
     Then @cat_count = @cat_count + 1  
     ELSE @cat_count = 1  
    3. SET @cat_id = column_cat_id  

3. 'COLUMN_COUNT_CONDITION_HERE' 
    1. count_column < count_number  

4. ' EXTRA THING ' 
    1. If you want to execute more than one statement inside " if stmt " 
    2. IF(condition, stmt1 , stmt2) 
     1. stmt1 :- CONCAT(exp1, exp2, exp3) 
     2. stmt2 :- CONCAT(exp1, exp2, exp3) 
    3. Final "If" Stmt LIKE 
     1. IF (condition , CONCAT(exp1, exp2, exp3) , CONCAT(exp1, exp2, exp3))  
Powiązane problemy