2010-06-25 2 views
4

У меня есть две таблицы players и scores.Присоединиться к одной строке из таблицы в MySQL

Я хочу, чтобы сгенерировать отчет, который выглядит примерно так:

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. Какое лучшее обходное решение здесь?

ответ

6

Это проблема с наибольшей проблемой n-группы, которая часто возникает при переполнении стека.

Вот мой обычный ответ:

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 является самой ранней.


Ваш комментарий относительно связей: у вас должна быть политика, для которой можно использовать в случае галстука. Одна из возможностей заключается в том, что вы используете автоматические инкрементные первичные ключи, тот, который имеет наименьшее значение, является более ранним. См дополнительный член в внешнем соединение ниже:

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, помните, что этот тип запросов сильно выгоден из нужного индекса.

+0

+1: Есть ли у вас шанс сравнить ваш и мой подход? Мне любопытно, если кто-то более эффективен, но я склоняюсь к вашему из-за того, как MySQL обрабатывает LEFT JOIN/IS NULL ... –

+0

, если в моих оценках 'join s ...' больше условий соединения, чем 's.player_id = p .id', скопировал бы все эти условия для «левых оценок внешнего соединения s2 ...»? –

+0

@OMG Ponies: Я обнаружил, что использование GROUP BY в MySQL является убийцей производительности, поскольку MySQL почти всегда создает временную таблицу. Принимая во внимание, что с использованием внешнего решения соединения (или эквивалентного NOT EXISTS с коррелированным подзапросом) можно использовать индексы покрытия, и поэтому объединение может быть выполнено в памяти. –

0

Большинство RDMBs даже не позволяют включать неагрегатные столбцы в предложение SELECT при использовании GROUP BY. В MySQL вы получите значения из случайных строк для своих неагрегатных столбцов. Это полезно, если вы действительно имеете одинаковое значение в определенном столбце для всех строк. Поэтому хорошо, что MySQL не ограничивает нас, хотя это важно понять.

Целая глава посвящена этому в SQL Antipatterns.

+1

Спасибо, Маркус! :) Также вы можете заставить MySQL вести себя более стандартно с 'SET SQL_MODE = ONLY_FULL_GROUP_BY' –

+0

Кстати, @Bill Karwin (писатель - принятый ответ на этот вопрос), оказывается, является автором этой книги! Маленький мир :) –

Смежные вопросы