2009-06-25 12 views
4

Ich habe eine Tabelle mit Kategorie, Produkt und Anzahl. Alle ganzen Zahlen. Ich suche die effizienteste Abfrage, die mir die Top-10-Produkte (höchste Anzahl) für jede Kategorie geben wird.Mysql Join mit Limit?

Ich habe mehrere Subselects und Joins versucht, konnte aber nicht herausfinden, wie es in einer einzigen Abfrage zu tun. Danke für Ihre Hilfe.

Antwort

7
select a.* from t a where 10 > (
    select count(*) from t b 
    where b.category=a.category 
    and b.count<a.count 
) 

Ich denke, das ist das, was Sie brauchen.

2

This article adressiert Ihr Problem, denke ich.

Grundsätzlich heißt es, dass, wenn Ihr Tisch klein ist, können Sie eine Selbst Ungleichheit tun verbinden, wie folgt aus:

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; 

Es ist eine teure Operation, aber für einen kleinen Tisch sollten Sie in Ordnung sein. Wenn Sie eine große Tabelle haben, sollten Sie dies mit einer Abfrage vergessen und einen anderen Ansatz für die Lösung implementieren.

0
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 
) 

Ich denke, dass dies ein guter Weg ist, aber mysql kehrt:

MySQL 返回:文档 
#1235 - This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' 
4

Eine etwas Abfrage aus diesem Artikel in meinem Blog geändert:

 

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) 

Sie benötigen einen zusammengesetzten Index für (category, count, id) schaffen für diese effizient zu arbeiten .

Beachten Sie die Verwendung von l.category >= lo.category AND l.category <= lo.category statt bloßer: l.category = lo.category

Dies ist ein Hack MySQL Verwendung effizienter Range check for each record

1
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; 
zu machen