2012-04-01 7 views
4

MySQLテーブルから複数の「トップX」結果を取得するより良い方法はありますか?異なるFOOの数が少ない場合、私は労働組合で簡単にこれを実現することができるよ:私は明らかにFOOの値ごとに労働組合を追加し続けることができMySQLテーブルの各個人のトップXレコードを選択してください

(SELECT foo,score FROM tablebar WHERE (foo = 'abc') ORDER BY score DESC LIMIT 10) 
UNION 
(SELECT foo,score FROM tablebar WHERE (foo = 'def') ORDER BY score DESC LIMIT 10) 

。しかし、fooに500以上の異なる値があり、それぞれのトップXが必要な場合、これは実用的ではありません。

+0

多分現在のパフォーマンスに近いところでも解決策があります – zerkms

答えて

9

このようなクエリは、グループごとの上位10個のスコアが「foo」の値になるようにする「グループごとの最大」という意味で言い換えることができます。

質問を実行して段階的に最適化する方法から始めて、この質問を驚くほど詳しく扱うthis linkをご覧ください。あなたは(すなわちGROUP BY fooをやって想像)fooすべてレベルにわたってこれを実行したい場合は

set @num := 0, @foo := ''; 
select foo, score 
from (
    select foo, score, 
     @num := if(@foo = foo, @num + 1, 1) as row_number, 
     @foo := foo as dummy 
    from tablebar 
    where foo IN ('abc','def') 
    order by foo, score DESC  
) as x where x.row_number <= 10; 

することは、あなたはwhere foo in ...ラインを省略することができます。

基本的に内側のクエリ(SELECT foo, score FROM tablebar WHERE foo IN ('abc','def') ORDER BY foo, score DESC)は降順スコア次いでfooことにより、第1注文と、テーブルからfooscoreグラブ。

@num := ...は1行ごとに増加し、新しい値がfooになるごとに1にリセットされます。つまり、@numは単なる行番号/ランクです(内側のクエリを独自に実行して、意味を調べてみてください)。

外部クエリは、次に、ランク/行数が10以下である行を選択

注:

UNIONを使用して元のクエリは、重複を削除した場合のでfoo='abc'ためのトップ10スコアがすべて100の場合、(foo,score)ペアが10回複製されるため、1つの行のみが返されます。これは重複を返します。

+0

あなたは私の検索でリンクしたページに実際に遭遇しましたが、すばやく一目瞭然であると誤って思っていました各グループの行。私はそれを詳しく見ていたはずです。 – Exupery

関連する問題