3

我有一个看似简单的任务,但我似乎无法使用 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

我试图用它来获得创意/hacky......它很接近但不正确:

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;

临时工作解决方案(HACKY):

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
4

2 回答 2

2

这个问题没有简单的单一查询解决方案,它是基于需要自联接的临时表(具有计数的表)的分组最大问题。假设您的数据库足够大(否则只使用您的 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 

您可以使用触发器或定期运行更新查询来更新此表(用户真的需要直到最后一秒的信息吗?可能不需要...)并节省大量处理,因为在索引表上查找每个类别的大多数点击需要很多使用经典的 group-wise 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
于 2012-04-17T19:06:36.677 回答
0

在这里暗中拍摄。您是否尝试过选择 DISTINCT cat_id

于 2012-04-17T17:09:11.983 回答