2012-04-26 18 views
6

Ciężko mi to zrobić bez przeszukiwania tego samego stołu co najmniej dwa razy, aby pobrać maksymalny wiersz, a następnie pobrać wartość dla tego wiersza. Ta tabela jest dość duża, więc jest to niedopuszczalne.Powróć wiersz z maksymalną wartością jednej kolumny na grupę

Oto co moja tabela może wyglądać tak:

SCORES 
ID ROUND SCORE 
1  1  3 
1  2  6 
1  3  2 
2  1  10 
2  2  12 
3  1  6 

muszę zwrócić wynik, że każde ID dostał w ostatniej rundzie. Oznacza to, że rząd ma maks. (Rundę), ale nie maksymalną liczbę punktów.

OUTPUT: 
ID ROUND SCORE 
1 3  2 
2 2  12 
3 1  6 

Teraz mam:

SELECT * FROM 
(SELECT id, round, 
CASE WHEN (MAX(round) OVER (PARTITION BY id)) = round THEN score ELSE NULL END score 
FROM 
SCORES 
where id in (1,2,3) 
) scorevals 
WHERE 
scorevals.round is not null; 

To działa, ale jest bardzo nieefektywne (muszę ręcznie odfiltrować wszystkie z tych wierszy, kiedy należy po prostu być w stanie nie chwycić te wiersze w pierwsze miejsce.)

Co mogę zrobić, aby uzyskać prawidłowe wartości?

Odpowiedz

4

jest to również możliwe bez podzapytaniu:

SELECT DISTINCT 
     id 
     ,max(round) OVER (PARTITION BY id) AS round 
     ,first_value(score) OVER (PARTITION BY id ORDER BY round DESC) AS score 
FROM SCORES 
WHERE id IN (1,2,3) 
ORDER BY id; 

Returns dokładnie co prosiłeś.
Najważniejsze jest to, że DISTINCT jest stosowany po funkcji okna.

SQL Fiddle.

Może szybciej, ponieważ używa tego samego okna dwukrotnie:

SELECT DISTINCT 
     id 
     ,first_value(round) OVER (PARTITION BY id ORDER BY round DESC) AS round 
     ,first_value(score) OVER (PARTITION BY id ORDER BY round DESC) AS score 
FROM SCORES 
WHERE id IN (1,2,3) 
ORDER BY id; 

przeciwnym razie robi to samo.

+0

mi się podoba; bardzo czysto. – Jeremy

3

Jesteś na dobrej drodze, używając funkcji analitycznych. Ale prawdopodobnie chcesz coś takiego z funkcją rank

SELECT * 
    FROM (SELECT a.*, 
       rank() over (partition by id order by round desc) rnk 
      FROM scores 
     WHERE id IN (1,2,3)) 
WHERE rnk = 1 

Jeśli nie może być krawaty (wiersze, które mają taką samą id i round) może chcesz użyć analityczną funkcję row_number zamiast rank - że będzie arbitralnie wybierz jeden z dwóch powiązanych wierszy, aby uzyskać rnk z 1 zamiast zwracać oba jako rank.

Jeśli chcesz korzystać z funkcji analitycznej MAX, można też zrobić coś takiego

SELECT * 
    FROM (SELECT a.*, 
       MAX(round) OVER (partition by id) max_round 
      FROM scores 
     WHERE id IN (1,2,3)) 
WHERE round = max_round 
0

Dla tego rodzaju problemu, to zazwyczaj wykorzystuje się max...keep...dense_rank konstrukt:

select 
    id, 
    max(round) round, 
    max(score) keep (dense_rank last order by round) score 
from 
    tq84_scores 
group by 
    id; 

sql fiddle

Powiązane problemy