Mysql Присоединиться с лимитом? - PullRequest
4 голосов
/ 25 июня 2009

У меня есть таблица с категорией, продуктом и количеством. Все целые числа. Я ищу наиболее эффективный запрос, который даст мне 10 лучших продуктов (наибольшее количество) для каждой категории.

Я пробовал несколько подвыборов и объединений, но не мог понять, как это сделать в одном запросе. Спасибо за вашу помощь.

Ответы [ 5 ]

7 голосов
/ 26 июня 2009
select a.* from t a where 10 >  (
   select count(*) from t b 
   where b.category=a.category 
   and b.count<a.count
) 

Я думаю, это то, что тебе нужно.

4 голосов
/ 26 июня 2009

Слегка измененный запрос из этой статьи в моем блоге:

SELECT  l.*
FROM    (
        SELECT  category,
                COALESCE(
                (
                SELECT  count
                FROM    mytable li
                WHERE   li.category = dlo.category
                ORDER BY
                        li.category DESC, li.count DESC, li.id DESC
                LIMIT 9, 1
                ), CAST(-1 AS DECIMAL)) AS mcount
                COALESCE(
                (
                SELECT  id
                FROM    mytable li
                WHERE   li.category = dlo.category
                ORDER BY
                        li.category DESC, li.count DESC, li.id DESC
                LIMIT 9, 1
                ), CAST(-1 AS DECIMAL)) AS mid
        FROM    (
                SELECT  DISTINCT category 
                FROM    mytable dl
                ) dlo
        ) lo, mytable  l
WHERE   l.category >= lo.category 
        AND l.category <= lo.category
        AND (l.count, l.id) >= (lo.mcout, lo.id)

Вам необходимо создать составной индекс на (category, count, id), чтобы это работало эффективно.

Обратите внимание на использование l.category >= lo.category AND l.category <= lo.category вместо простого: l.category = lo.category

Это хак, чтобы заставить MySQL эффективно использовать Range check for each record

2 голосов
/ 25 июня 2009

Эта статья , я думаю, решает вашу проблему.

В основном, это говорит о том, что если ваш стол маленький, вы можете сделать соединение само-неравенства, например:

SELECT t1.*, COUNT(*) AS countRank
FROM tbl AS t1
JOIN tbl AS t2 ON t1.category=t2.category AND t1.count <= t2.count
GROUP BY t1.category, t1.count
HAVING countRank <= 10
ORDER BY category,count DESC;

Это дорогая операция, но с маленьким столом все будет в порядке. Если у вас большая таблица, вы должны забыть сделать это одним запросом и реализовать другой подход к решению.

1 голос
/ 29 октября 2010
SET @row = 0;
SET @category = 0;
 
SELECT top.*
FROM (
  SELECT IF(@category = p.cId, @row := @row + 1, @row := 1) rowNumber,
    (@category := p.cId) categoryId,
    p.pId
  FROM (
    SELECT c.cId,
      c.pId
    FROM prod pr
      INNER JOIN cat_prod c ON c.pId = pr.id
    GROUP BY c.cId, c.pId
    ) p
  ) top
HAVING top.rowNumber < 4;
0 голосов
/ 25 июня 2009
select a.* from `table` a where a.product in (
    select b.product from `table` b 
    where b.category=a.category 
    order by b.count desc 
    limit 10
)

Я думаю, что это хороший способ, но mysql возвращает:

 MySQL 返回:文档
#1235 - This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...