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

私はそれで創造的/ハッキーになろうとしました...それは近いですが正しくありません:

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;

TEMP WORKING ソリューション (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 

トリガーを使用するか、更新クエリを定期的に実行してこのテーブルを更新することができます (ユーザーは本当に最後の 1 秒まで情報を必要としますか? おそらくそうではないでしょう...)。インデックス付きテーブルの各カテゴリのほとんどのクリックを見つけるには多くの処理が必要になるため、多くの処理を節約できます。従来のグループごとの最大アプローチを使用して時間を短縮:

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

ここで暗所撮影。Select DISTINCT cat_id を試しましたか

于 2012-04-17T17:09:11.983 に答える