从另一个表中获取第3个表中每一行的前3个

时间:2013-12-15 17:07:30

标签: mysql greatest-n-per-group

我有3个表,一个存储图片,一个存储图片投票(picturespicture_votes)。最后一个表是categories,它存储图片可以属于的不同类别。

以下是表格(省略了非相关栏目);

- Table `pictures`
picture_id  INT
category_id INT

- Table `picture_votes`
vote        TINYINT
picture_id  INT

最后

- Table `categories`
category_id INT

我想要做的是是为每个类别选择前3个最多投票的图片。

我真的迷路了,不知道如何最有效地做到这一点。

3 个答案:

答案 0 :(得分:2)

如果您可以在每个类别的一行中接受它们作为逗号分隔列表:

select pv.category_id,
       substring_index(group_concat(pv.picture_id order by numvotes desc), ',', 3) as Top3
from (select p.category_id, p.picture_id, count(*) as numvotes
      from picture_votes pv join            
           pictures p             
           on p.picture_id = pv.picture_id
      group by p.category_id, p.picture_id
     ) pv
group by pv.category_id;

答案 1 :(得分:0)

我想出了这个;

(SELECT p.*
 FROM
  pictures p
 LEFT JOIN
  picture_votes pv
   ON pv.picture_id = p.picture_id
 WHERE p.category_id = n
 GROUP BY p.picture_id
 ORDER BY SUM(pv.vote) DESC
 LIMIT 3)
 UNION
 (SELECT ...)
 UNION
 (SELECT ...)
 --And so on for every category_id (there are 9)

这看起来像是一个糟糕的解决方案,查询时间太长了。

答案 2 :(得分:0)

sqlFiddle

SELECT category_id,picture_id,ranking FROM
(
 select c.category_id,(select p.picture_id
                  from pictures p, picture_votes pv
                  where p.picture_id = pv.picture_id
                  and p.category_id = c.category_id
                  group by p.picture_id
                  order by sum(pv.vote) desc
                  limit 0,1)as picture_id,1 as ranking
   from categories c

 union

 select c.category_id,(select p.picture_id
                  from pictures p, picture_votes pv
                  where p.picture_id = pv.picture_id
                  and p.category_id = c.category_id
                  group by p.picture_id
                  order by sum(pv.vote) desc
                  limit 1,1)as picture_id,2 as ranking 
   from categories c

 union
 select c.category_id,(select p.picture_id
                  from pictures p, picture_votes pv
                  where p.picture_id = pv.picture_id
                  and p.category_id = c.category_id
                  group by p.picture_id
                  order by sum(pv.vote) desc
                  limit 2,1)as picture_id,3 as ranking
   from categories c
)result
WHERE picture_id is not null
order by category_id asc,ranking asc

或此sqlFiddle

SELECT picture_id,category_id,sumvotes,voteOrder
FROM
    (SELECT picture_id,category_id,sumvotes,
       IF(@prevCat <> category_id,@voteOrder:=1,@voteOrder:=@voteOrder+1)
       as voteOrder,
       @prevCat:=category_id
     FROM(SELECT p.picture_id,
                 p.category_id,
                 SUM(pv.vote) as sumvotes
          FROM pictures p
          JOIN picture_votes pv
          ON p.picture_id = pv.picture_id
          GROUP BY p.picture_id,
                   p.category_id
          ORDER BY p.category_id, sumvotes DESC
          )as ppv,
     (SELECT @prevCat:=0,@voteOrder:=0)pc
     )finalTable
WHERE voteOrder BETWEEN 1 AND 3
ORDER BY category_id ASC, voteOrder ASC