项目中经常会遇到对数据进行分组排序并取前N条的需求,比如有一张资讯表如下
CREATE TABLE `test_news` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(100) DEFAULT NULL COMMENT '文章标题',
`content` longtext COMMENT '文章内容',
`channel` int(11) DEFAULT NULL COMMENT '文章频道',
`status` int(11) DEFAULT NULL COMMENT '状态,1正常,0关闭',
`create_time` datetime DEFAULT NULL COMMENT '文章发布时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=513 DEFAULT CHARSET=utf8;
文章分为多个频道,比如体育新闻、娱乐新闻、财经新闻、汽车新闻等多个频道,现在要求取出每种类型的最新的前5条新闻,避免多次进行数据库连接我们肯定不能每种类型都单独去请求数据库查询,假如种类不多的话我们可以分别查出每种新闻的前5条然后使用union all进行合并,这样也只需要进行一次数据库连接,除了这种方法还有以下两种方法。
方法一:
由于设置了表的id自增,所以最新的资讯可以根据id来倒序查也可根据创建时间create_time来进行倒序,这里采用的id,要取5条最新资讯,所以查询的count需要小于5
思路:遍历所有资讯与当前资讯做比较,同一频道且相同状态的资讯不超过5个当前的id大,那么这条资讯才算最新的前5条
SELECT
id,
title,
channel,
create_time
FROM
test_news AS a
WHERE
(
SELECT
count(1)
FROM
test_news AS b
WHERE
a.channel = b.channel
AND a. STATUS = b. STATUS
AND a.id < b.id
) < 5
ORDER BY
a.channel ASC,
a.id DESC;
方法二:
SELECT
a.id,
a.title,
a.channel,
a.create_time
FROM
test_news AS a
LEFT JOIN test_news AS b ON a.channel = b.channel
AND a. STATUS = b. STATUS
AND a.id < b.id
WHERE
a. STATUS = 1
GROUP BY
a.channel,
a.id
HAVING
count(1) < 5
ORDER BY
a.channel ASC,
a.id DESC;