我想从每个类别(4个类别)获得访问量最大的文章

时间:2013-02-13 15:20:52

标签: mysql sql select group-by

我在数据库的表格中有 4个类别 我想从数据库中的每个类别中获取最常访问的四篇文章 这意味着从(4 articles most visited from category1)获取(4 articles most visited from category2) + (4 articles most visited from category3) + (4 articles most visited from category4) + 16 articles =总4 categories

我想通过一个查询来做到这一点。

普通查询:

$sql="select ID,name,country from article where `active`='yes' order by `visit` desc limit 16 ";

文章表格结构:

CREATE TABLE `article` (
  `ID` int(11) NOT NULL auto_increment,
  `name` varchar(255) NOT NULL default '',
  `country` varchar(50) NOT NULL default '',
  `town` varchar(30) NOT NULL default '',
  `other_town` varchar(30) NOT NULL default '',
  `title` varchar(255) NOT NULL default '0',
  `size` varchar(30) NOT NULL default '',
  `type` varchar(30) NOT NULL default '',
  `tel` varchar(30) NOT NULL default '',
  `mobile` varchar(30) NOT NULL default '',
  `connect` varchar(30) NOT NULL default '',
  `email` varchar(30) NOT NULL default '',
  `photo1` varchar(100) NOT NULL default '',
  `print` varchar(30) NOT NULL default '',
  `small_pic1` varchar(100) NOT NULL default '',
  `detail` text NOT NULL,
  `add_by` int(11) NOT NULL default '0',
  `cat` int(11) NOT NULL default '0',
  `goods_type` enum('new','old') NOT NULL,
  `add_date` date NOT NULL default '0000-00-00',
  `end_date` date NOT NULL default '0000-00-00',
  `period` varchar(30) NOT NULL default '',
  `visit` int(11) NOT NULL default '0',
  `comment` int(30) NOT NULL default '0',
  `fav` varchar(15) NOT NULL default '',
  `favorite` varchar(15) NOT NULL default '',
  `active` varchar(15) NOT NULL default '',
  `rate` int(11) NOT NULL default '0',
  `short` text NOT NULL,
  `add_to` varchar(50) NOT NULL default '',
  `author` varchar(50) NOT NULL default '',
  `author_img` varchar(50) NOT NULL default '',
  `lang` varchar(10) NOT NULL default '',
  `budget` varchar(50) NOT NULL default '',
  PRIMARY KEY  (`ID`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 ;

类别表格结构:

CREATE TABLE `category` (
  `ID` int(11) NOT NULL auto_increment,
  `name` varchar(255) NOT NULL default '',
  `img` varchar(255) NOT NULL default '',
  `sub` int(11) NOT NULL default '0',
  `type` varchar(20) NOT NULL default '',
  `lang` varchar(10) NOT NULL default '',
  `active` varchar(25) NOT NULL default '',
  `add_by` int(11) NOT NULL default '0',
  PRIMARY KEY  (`ID`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

3 个答案:

答案 0 :(得分:1)

这可以做到,但并非100%直截了当。我将这篇文章加入了我之前阅读的SO问题的书签(也将尝试查找/链接)。基本上,如果你想要每个查询一个组,你可以使用ORDER BY和LIMIT,但是要在一个查询中执行所有操作,请按照链接的文章进行详细介绍。

http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/

对于后人,我将尝试根据他提供的第一种方法发布一个示例摘要查询,该查询可以按照与类别数量成比例的指数级增长:

select ID, name, country, cat, visit
from article
where visit = (select max(visit) from article as a where a.cat = article.cat)
or visit = (select max(visit) from article as a where a.cat = article.cat
   and visit < (select max(visit) from article as a2 where a2.cat = article.cat))

or visit = (select max(visit) from article as a where a.cat = article.cat
  and a.visit < (select max(a2.visit) from article as a2 where a2.cat = article.cat
  and a2.visit < (select max(a3.visit) from article as a3 where a3.cat = article.cat)))

or visit = (select max(visit) from article as a where a.cat = article.cat
  and a.visit < (select max(a2.visit) from article as a2 where a2.cat = article.cat
  and a2.visit < (select max(a3.visit) from article as a3 where a3.cat = article.cat
  and a3.visit < (select max(a4.visit) from article as a4 where a4.cat =    article.cat))))
order by cat, visit desc

或者,如果您希望订单不指定类别,只需按访问desc

订购

这将返回每个类别中的前四个,但请注意每个级别深层次的查询嵌套,如果您需要继续深入,请按照他的说明获取更好的选项(他,我会描述这个如YUCK)。

SQL小提琴:http://www.sqlfiddle.com/#!2/e115f/26

对于后代,我的测试数据:

CREATE TABLE article (
 ID int auto_increment primary key, 
 name varchar(20), 
 country varchar(30),
 cat int,
 visit int
);

INSERT INTO article (name, country, cat, visit) VALUES
 ('Test1', 'Canada', 1, 7),('Test2', 'Canada', 1, 2),('Test3', 'Ireland', 1, 1),
 ('Test5', 'Ireland', 1, 3),('Test6', 'Ireland', 1, 8),('Test7', 'India', 1, 9),
 ('Test8', 'Canada', 2, 11),('Test9', 'Canada', 2, 13),('Test10', 'Ireland', 2, 6),
 ('Test11', 'Ireland', 2, 5),('Test12', 'Ireland', 2, 1),('Test13', 'India', 3, 1),
 ('Test14', 'India', 3, 9),('Test15', 'India', 3, 8),('Test16', 'India', 3, 54);

答案 1 :(得分:1)

这应该这样做。基本上确定每个类别的行号,然后按访问列排序并选择前4个。这是一个精简版本,但应该得到指向(添加您需要返回的字段):

SELECT Id, Cat, Visit, Name
FROM (
    SELECT 
      @curRow:=CASE WHEN @prevRow = A.cat THEN @curRow+1 ELSE 1 END AS rn,
      A.Id, 
      A.Visit,
      A.Cat, A.Name, 
      @prevRow:=A.cat AS clset
    FROM (SELECT A.Id, C.Id as Cat, A.Visit, C.Name
          FROM Articles A
            JOIN Category C ON A.cat = C.id
          ORDER BY A.Cat, A.Visit DESC
          ) A
      JOIN (SELECT @curRow:=0) r
      JOIN (SELECT @prevRow:=0) r2
  ) B
  WHERE rn <= 4

还有一些小提琴:http://sqlfiddle.com/#!2/b7260/1

祝你好运。

答案 2 :(得分:0)

试试这个:

SELECT ID, NAME, country, catCnt 
FROM (SELECT ID, NAME, country, cat, IF(@cat=(@cat:=cat), @cnt:=@cnt+1, @cnt:=1) catCnt 
      FROM (SELECT ID, NAME, country, cat FROM article WHERE `active`='yes' ORDER BY cat, `visit` DESC) A, 
           (SELECT @cat := 0, @cnt:=1) B
      ) A 
GROUP BY cat HAVING catCnt <= 4;

SELECT ID, NAME, country
FROM (SELECT ID, NAME, country, cat, IF(@cat=(@cat:=cat), @cnt:=@cnt+1, @cnt:=1) catCnt 
      FROM (SELECT ID, NAME, country, cat FROM article WHERE `active`='yes' ORDER BY cat, `visit` DESC) A, 
           (SELECT @cat := 0, @cnt:=1) B
      ) A 
WHERE catCnt <= 4;