MySQL выбирает лучшие X записей для каждого человека в таблице - PullRequest
4 голосов
/ 02 апреля 2012

Есть ли лучший способ получить несколько результатов "top X" из таблицы MySQL?Я могу легко сделать это с помощью объединения, когда число различных foo мало:

(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+ различных значений для foo, и мне нужен верхний X каждого.

1 Ответ

10 голосов
/ 02 апреля 2012

Этот тип запроса может быть перефразирован в смысле «наибольший n на группу», где вы хотите, чтобы первые 10 баллов на «группу» были значениями «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;

Если вы хотите выполнить это на всех уровнях foo (т.е. представьте, что делаете GROUP BY foo), вы можете опустить строку where foo in ....

В основном внутренний запрос (SELECT foo, score FROM tablebar WHERE foo IN ('abc','def') ORDER BY foo, score DESC) захватывает foo и score из таблицы, упорядочивая сначала по foo, а затем по убыванию.

@num := ... просто увеличивает каждую строку, сбрасывая в 1 для каждого нового значения foo. То есть @num - это просто номер строки / ранг (попробуйте выполнить внутренний запрос самостоятельно, чтобы понять, что я имею в виду).

Затем внешний запрос выбирает строки, где ранг / номер строки меньше или равен 10.

Примечание:

Ваш исходный запрос с UNION удаляет дубликаты, поэтому, если все первые 10 баллов для foo='abc' равны 100, будет возвращена только одна строка (поскольку пара (foo,score) реплицируется 10 раз). Этот вернет дубликаты.

...