从M组中选择前N行

时间:2011-10-24 00:07:02

标签: mysql group-by rows greatest-n-per-group

我有这张桌子:

CREATE TABLE IF NOT EXISTS `catalog_sites` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `cat_id` int(10) unsigned NOT NULL,
  `date` datetime NOT NULL,
  `url` varchar(255) NOT NULL,
  `title` varchar(255) NOT NULL,
  `description` varchar(255) NOT NULL,
  `keywords` varchar(255) NOT NULL,
  `visited` int(10) unsigned NOT NULL,
  `shown` int(10) unsigned NOT NULL,
  `meta_try` int(1) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `url` (`url`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

我认为我的问题很简单,但似乎无法找到合适的解决方案..

所以,这是一个包含网站的表格,我想获得6个不同类别的6个网站(cat_id,总计:36行),每个类别的评分最高。评分计算为visited / shown

我应该得到包含6个顶级类别的36行(我们可以通过AVG(visited / shown)排序找到它们),以及这6个类别中的6个顶级网站。

如果您有任何想法可能会以不同的方式发生,请告诉我。

2 个答案:

答案 0 :(得分:2)

这应该可以使用MySQL变量获得你想要的内容,内部查询将预先计算访问/显示的排名,并按你想要的条件使用顺序...每个类别,最高排名......然后使用@vars将@RankSeq顺序保持1-?每个类别。从该Prequery(别名PQ)开始,OUTER查询只查询PreQ,其中URL的排名顺序为< = 6

为了进一步确保您只获得前6个类别,内部PreQuery还具有“TopCategories”(别名)的预查询/限制

select
      PQ.URL,
      PQ.Cat_ID,
      PQ.Rank,
      PQ.URLRankSeq
   from 
      ( select 
              CS.cat_id,
              (CS.visited / CS.shown ) as Rank,
              CS.url,
              @RankSeq := if( @LastCat = CS.Cat_ID, @RankSeq +1, 1 ) URLRankSeq,
              @LastCat := CS.Cat_ID as ignoreIt
           from
              ( select cat_id, 
                       avg( visited / shown )
                   from catalog_sites
                   group by 1
                   order by 2 desc
                   limit 6 ) TopCategories

              JOIN catalog_sites CS
                 on TopCategories.Cat_ID = CS.Cat_ID,

              (select @RankSeq := 0, @LastCat = 0 ) SQLVars   
           order by 
              CS.cat_id,
              Rank ) PQ
    where
      PQ.URLRankSeq <= 6

答案 1 :(得分:1)

我已经尝试了你的例子,但它对我来说并不适用,或者我只是不知道如何使它适应我的情况。无论如何,就SQL而言,我仍然是一个菜鸟,所以我无法理解你的查询。

但我设法解决了我的问题。这很复杂,可能是最糟糕的方法。它也很慢,但我会缓存结果,所以这应该不是问题。

这是我的解决方案:

SET @site_limit = 2;
SET @cat_limit = 6;

SET @row = 0;
SET @limiter = 0;
SET @last_cat = 0;

SELECT `cat_id`, `url`, `visited` / `shown` AS `rating`, @limiter := IF(@last_cat = `cat_id`, IF(@limiter >= @site_limit - 1, @limiter, @limiter + 1), 0) AS `limiter`, @last_cat := `cat_id` AS `last_cat`
FROM `catalog_sites`
WHERE `cat_id`
IN (
    SELECT `cat_id`
    FROM (
        SELECT `cat_id`, @row := @row + 1 AS `row`
        FROM (
            SELECT `cat_id`
            FROM `catalog_sites`
            GROUP BY `cat_id`
            ORDER BY AVG(`visited` / `shown`) DESC
        ) AS derived1
    ) AS derived2
    WHERE `row` <= @cat_limit
)
GROUP BY `cat_id`, `limiter`
ORDER BY `cat_id`, `rating` DESC