2012-04-26 11 views
6

最大行を取得するために同じテーブルを2回以上検索せずに、この行を実行するのは苦労しています。問題のテーブルはかなり大きいので、これは容認できません。私は、各IDが最新のラウンドで得た得点を返す必要がグループごとに1列の最大値を持つ行を返します

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

:ここ

は私のテーブルがどのようなものであるかです。つまり、最大(丸)の行であり、最大のスコアではありません。

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

今私が持っている:

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; 

これは動作しますが、かなり非効率的である私はちょうどでそれらの行をつかむないことができるはずとき(私は、手動でこれらのすべての行をフィルタリングする必要があります最初の場所。)

正しい値を取得するにはどうすればよいですか?

答えて

4

ような何かを行うことができます:あなたは尋ねた、まさに

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; 

戻ります。
重要な点は、DISTINCTがウィンドウ関数の後にに適用されていることです。

たぶん速く

SQL Fiddle.

それは二度同じウィンドウを使用しているので:

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; 

は、そうでなければ同じことをやって。この種の問題のために

+0

私はそれが好き。非常にきれいな。 – Jeremy

3

分析機能を使用して適切な軌道に乗っています。しかし、あなたはおそらくrank機能を備えたこのような何かをしたい絆あなたはrankの代わりにrow_number分析関数を使用することもできます(同じidroundを持つ行)があることができれば

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 

- それは任意になります2つの結ばれた行の1つを選択して、rankとして返すのではなく、rnkが1になるようにします。あなたはMAX分析関数を使用したい場合は

、あなたはまた、サブクエリなしでこれも可能である

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

、私はmax...keep...dense_rank構文を使用する傾向がある:

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

sql fiddle

関連する問題