查询以查找过去 30 天内点击次数最多的 16 个帖子,没有重复的类别


Query to find 16 most clicked posts in last 30 days without duplicated categories

我有一个看似简单的任务,但我似乎无法使用 1 个查询找到一个优雅的解决方案......

问题:我有一个记录的"帖子"点击"表,其中每个帖子都是"类别"的一部分。我想找到过去 30 天内点击率最高的 16 个帖子 - 但我想避免重复的类别

实际上看起来很简单,但我似乎被卡住了。

我知道如何在最近 30 次中获得最多的点击,但我不知道如何避免重复的猫。

SELECT cat_id,
       post_id,
       COUNT(post_id) AS click_counter
FROM   cs_coupon_clicks
WHERE  time_of_click > DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP  BY post_id
ORDER  BY click_counter DESC

我试图用它变得有创意/笨拙...它很接近但不正确:

SELECT cat_id,
       Max(sort) AS sortid
FROM   (SELECT cat_id,
               post_id,
               COUNT(post_id)                       AS click_counter,
               CONCAT(COUNT(post_id), '-', post_id) AS sort
               FROM   cs_coupon_clicks
               WHERE  time_of_click > DATE_SUB(NOW(), INTERVAL 30 DAY)
               GROUP  BY cat_id, post_id) t1
GROUP  BY cat_id
ORDER  BY cat_id ASC

任何帮助将不胜感激,因为我不是真正的MySQL专家。我最终可能只是做了一些PHP逻辑,但我很好奇解决此类问题的正确方法。

谢谢大家。

编辑(结构):

CREATE TABLE `cs_coupon_clicks` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`src` varchar(255) NOT NULL DEFAULT '',
`cat_id` int(20) NOT NULL,
`post_id` int(20) NOT NULL,
`tag_id` int(20) NOT NULL,
`user_id` int(20) DEFAULT NULL,
`ip_address` char(30) DEFAULT NULL,
`referer` varchar(255) NOT NULL,
`browser` varchar(10) DEFAULT NULL,
`server_var` text NOT NULL,
`time_of_click` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `cat_id` (`cat_id`),
KEY `post_id` (`post_id`),
KEY `user_id` (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

临时工作解决方案(黑客):

SELECT
  cat_id,
  MAX(sort) AS sortid
FROM (
  SELECT
    cat_id,
    post_id,
    COUNT(post_id) AS click_counter,
    RIGHT(Concat('00000000', COUNT(post_id), '-', post_id), 16) AS SORT
  FROM   cs_coupon_clicks
  WHERE  time_of_click > DATE_SUB(NOW(), INTERVAL 30 DAY)
  GROUP  BY cat_id, post_id
) AS t1
GROUP  BY cat_id
ORDER  BY sortid DESC

这个问题没有简单的单一查询解决方案,这是一个基于需要自联接的临时表(带有计数的表)的组级最大问题。假设你的数据库变得足够大(否则就去你的php逻辑),我会选择一个统计表,保存有关类别,帖子和点击次数的信息:

CREATE TABLE `click_cnts` (
 `cat_id` int(20) NOT NULL,
 `post_id` int(20) NOT NULL,
 `clicks` int(20) NOT NULL,
 PRIMARY KEY (`cat_id`,`post_id`),
 KEY `cat_id` (`cat_id`,`clicks`)
)

并使用与问题中第一个查询相同的查询来填充它:

INSERT INTO click_cnts(cat_id, post_id, clicks)
SELECT cat_id, post_id, COUNT(post_id) AS click_counter
      FROM   cs_coupon_clicks
      WHERE  time_of_click > NOW() - INTERVAL 30 DAY
      GROUP  BY cat_id,post_id 

您可以使用触发器或定期运行更新查询来更新此表(用户真的需要直到最后一秒的信息吗?可能不需要...)并节省大量处理,因为使用经典的组 max 方法查找索引表上每个类别的大多数点击需要更少的时间:

SELECT cg.cat_id, cu.post_id, cg.most_clicks 
FROM
( SELECT cat_id, max(clicks) as most_clicks FROM click_cnts
  GROUP BY cat_id ) cg
JOIN click_cnts cu 
ON cg.cat_id = cu.cat_id
AND cu.post_id = ( SELECT cc.post_id FROM click_cnts cc
                   WHERE cc.cat_id = cg.cat_id
                   AND cc.clicks = cg.most_clicks
                   LIMIT 1 )
ORDER BY cg.most_clicks DESC
LIMIT 16

在黑暗中拍摄。您是否尝试过选择不同的cat_id