4

私は2つのテーブルplayersとを持っていscoresます。

次のようなレポートを生成したいと思います。

player    first score             points
foo       2010-05-20              19
bar       2010-04-15              29
baz       2010-02-04              13

現在、私のクエリは次のようになっています。

select p.name        player,
       min(s.date)   first_score,
       s.points      points    
from  players p    
join  scores  s on  s.player_id = p.id    
group by p.name, s.points

戻るs.points行に関連付けられているが必要です。min(s.date)それはこのクエリで起こっていますか?つまりs.points、結合された行の正しい値を取得していることをどのように確認できますか?

補足:これは、MySQLの密なランキングの欠如に何らかの形で関連していると思います。ここでの最善の回避策は何ですか?

4

2 に答える 2

6

これは、StackOverflowで頻繁に発生するグループあたり最大の問題です。

これが私のいつもの答えです:

select
  p.name        player,
  s.date        first_score,
  s.points      points

from  players p

join  scores  s
  on  s.player_id = p.id

left outer join scores  s2
  on  s2.player_id = p.id
      and s2.date < s.date

where
  s2.player_id is null

;

言い換えると、スコアsが与えられた場合、同じプレーヤーのスコアs2を見つけようとしますが、日付は早くなります。以前のスコアが見つからない場合は、sが最も早いスコアです。


同点についてのコメントを再確認してください。同点の場合にどちらを使用するかについてのポリシーが必要です。1つの可能性は、自動インクリメントの主キーを使用する場合、値が最も小さいものが前のキーであるということです。以下の外部結合の追加用語を参照してください。

select
  p.name        player,
  s.date        first_score,
  s.points      points

from  players p

join  scores  s
  on  s.player_id = p.id

left outer join scores  s2
  on  s2.player_id = p.id
      and (s2.date < s.date or s2.date = s.date and s2.id < s.id)

where
  s2.player_id is null

;

基本的に、少なくとも特定のプレーヤーにとって一意であることが保証されている列に到達するまで、タイブレーカー用語を追加する必要があります。多くの場合、テーブルの主キーが最善の解決策ですが、別の列が適している場合もあります。

@OMG Poniesと共有したコメントに関して、このタイプのクエリは適切なインデックスから大きな恩恵を受けることを忘れないでください。

于 2010-06-25T18:26:58.183 に答える
0

ほとんどのRDMBでは、GROUP BYを使用するときに、SELECT句に非集計列を含めることさえできません。MySQLでは、非集計列のランダムな行からの値になります。これは、すべての行の特定の列に実際に同じ値がある場合に役立ちます。したがって、理解することは重要ですが、MySQLが私たちを制限しないのは素晴らしいことです。

SQLアンチパターンでは、この章全体を取り上げています。

于 2010-06-25T18:30:56.943 に答える