2009-06-25 7 views
4

J'ai une table avec la catégorie, le produit et le compte. Tous les entiers Je cherche la requête la plus efficace qui me donnera le top 10 des produits (nombre le plus élevé) pour chaque catégorie.Mysql Joindre avec limite?

J'ai essayé plusieurs sous-sélections et jointures, mais je n'ai pas réussi à comprendre comment le faire en une seule requête. Merci de votre aide.

Répondre

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

Je pense que c'est ce que vous avez besoin.

2

This article répond à votre problème je pense.

Fondamentalement, il est dit que si votre table est petite, vous pouvez faire une inégalité de jointure réflexive, comme ceci:

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; 

Il est une opération coûteuse, mais pour une petite table, vous devriez être très bien. Si vous avez une grande table, vous devriez oublier de le faire avec une requête et mettre en œuvre une approche différente de la solution.

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 
) 

Je pense que cela est une bonne façon, mais retourne mysql:

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

Une requête légèrement modifiée de cet article dans mon blog:

 

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) 

Vous devez créer un index composite sur (category, count, id) pour que cela fonctionne efficacement .

Notez l'utilisation de l.category >= lo.category AND l.category <= lo.category au lieu de simple: l.category = lo.category

Ceci est un hack pour faire MySQL une utilisation efficace 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;