group by分组中显示最大或者最小的一行数据
(2011-05-06 11:44:45)
标签:
groupby显示杂谈 |
分类: 技术 |
自己查了不少东西,看到这个文章不错,先直接复制过来,自己学到了不少东西,有时间再好好整理一下。
哪个显示在第一条?
类如 有一个 帖子的回复表,posts( id , tid , subject , message , dateline ) ,
id为 自动增长字段, tid为该回复的主题帖子的id(外键关联), subject 为回复标题, message 为回复内容, dateline 为回复时间,用UNIX 时间戳表示,
现在要求 选出 前十个来自不同主题的最新回复
SELECT * FROM posts GROUP BY tid LIMIT 10
这样一个sql语句选出来的并非你想要的 最新的回复,而是最早的回复,实际上是某篇主题的第一条回复记录!
也就是说 GROUP BY 语句没有排序,那么怎么才能让 GROUP 按照 dateline 倒序排列呢?加上 order by 子句?
看下面:
SELECT * FROM posts GROUP BY tid ORDER BY dateline DESC LIMIT 10
这条语句选出来的结果和上面的完全一样,不过把结果倒序排列了,而选择出来的每一条记录仍然是上面的记录,原因是 group by 会比
order by 先执行,这样也就没有办法将 group by 之前,也就是在分组之前进行排序了, 有网友会写出下面的sql
语句:
SELECT * FROM posts GROUP BY tid DESC ORDER BY dateline DESC LIMIT
10
也就是说 在 GROUP BY 的字段 tid
后面加上递减顺序,这样不就可以取得分组时的最后回复了吗?这个语句执行结果会和上面的一模一样,这里加上 DESC
和ASC对执行结果没有任何影响!其实这是一个错误的语句,原因是GROUP BY 之前并没有排序功能,mysql 手册上面说,GROUP
BY
时是按照某种顺序排序的,某种顺序到底是什么顺序?其实根本没有顺序,因为按照tid分组,其实也就是说,把tid相等的归纳到一个组,这样想的话,GROUP
BY tid DESC 可以认为是在按照 tid
分组的时候,按照tid进行倒序排列,这不扯吗,既然是按照tid分组,当然是tid相等的归到一组,而这时候按照tid倒叙还是升序有个P用!
于是有网友发明下面的语句:
SELECT * FROM posts GROUP BY tid , dateline DESC ORDER BY dateline
DESC LIMIT 10
心想这样我就可以在分组前按照 dateline 倒序排列了,其实这个语句并没有起到按照tid分组的作用,原因还是上面的,在group
by 字段后加 desc 还是 asc 是错误的写法,而这种写法 网友本意是想 按照 tid 分组,并且在分组的时候按照
dateline排倒序!而实际这句相当于下面的写法:(去掉 GROUP BY 字段后面的 DESC)
SELECT * FROM posts GROUP BY tid , dateline ORDER BY dateline DESC
LIMIT 10
也就是说,按照 tid 和 dateline 联合分组,只有在记录tid和dateline 同时相等的时候才归纳到一组,这显然不可能,
因为 dateline 时间线基本上是唯一的!
有人写出下面的语句:
SELECT *,max(dateline) as max_line FROM posts GROUP BY tid ORDER BY
dateline DESC LIMIT 10
这条语句的没错是选出了最大发布时间,但是你可以对比一下 dateline 和 max_dateline
并不相等!(可能有相当的情况,就是分组的目标记录只有一条的时候!)
为什么呢?原因很简单,这条语句相当于是 在group by 以后选出 本组的最大的
发布时间!对分组没有起到任何影响!因为SELECT子句是最后执行的!
后来更有网友发明了下面的写法!
SELECT *,max(dateline) as max_line FROM posts GROUP BY tid HAVING
dateline=max(dateline)
ORDER BY dateline DESC LIMIT 10
这条语句的预期结果和想象中的并不相同!因为你会发现,分组的结果中大量的记录没有了!为什么?因为 HAVING
是在分组的时候执行的,也就说:在分组的时候加上一个这样的条件:选择出来的 dateline 要和 本组最大的dateline
相等,执行的结果和下面的语句相同:
SELECT *,max(dateline) as max_line FROM posts GROUP BY tid HAVING
count(*)=1
ORDER BY dateline DESC LIMIT 10
看了这条sql语句是不是明白了呢?
dateline=max(dateline) 只有在分组中的记录只有一条的时候才成立,原因很明白吧!只有一条他才会和本组的最大发布时间相等阿,(默认dateline为不重复的值)
原因还是因为 group by 并没有排序功能,所有的这些排序功能只是错觉,所以你最终选出的 dateline
和max(dateline) 永远不可能相等,除非本组的记录只有一条!GROUP BY
在分组的时候,可能是一个一个来找的,发现有相等的tid,去掉,保留第一个发现的那一条记录,所以找出来的
记录永远只是按照默认索引顺序排列的!
那么说了这么多,到底有没有办法让 group by 执行前分组阿?有的 ,子查询阿!
最简单的 :
SELECT cid, aid, title, stitle, image, author, postdate FROM
news_content WHERE aid IN(SELECT DISTINCT aid FROM cate_links where
cid='3') AND status=0 ORDER BY postdate DESC
limit 10
SELECT distinct n.cid, n.aid, n.title, n.stitle, n.image, n.author,
n.postdate FROM news_content n, cate_links c WHERE c.cid=3 AND
n.aid=c.aid AND n.status=0 ORDER BY n.postdate
DESC limit 10 比上面的快
select *,concat(aid,cid) as ac from cate_links where cid='3';
1135
select *,concat(aid,cid) as ac from cate_links where cid='3' group
by
ac;
SELECT * FROM cate_links where cid='3' group by concat(aid,cid)
721
select max(autoid),concat(aid,cid) as ac from cate_links where
cid='3' group by ac; 721
select max(autoid) from cate_links where cid='3' group by
concat(aid,cid);
select *,max(autoid) from cate_links where cid='3' group by
concat(aid,cid) HAVING
autoid=max(autoid);
select * from cate_links where cid='3' group by concat(aid,cid)
HAVING
autoid=max(autoid);
SELECT aid FROM (SELECT * FROM cate_links as a where cid='3' order
by autoid DESC) as b group by concat(aid,cid) 721
delete from cate_links where autoid not IN (SELECT autoid FROM
(SELECT * FROM cate_links as a where cid='3' order by autoid DESC)
as b group by concat(aid,cid)); 11秒
delete from cate_links where autoid not IN (SELECT autoid FROM
(SELECT * FROM cate_links as a order by autoid DESC) as b group by
concat(aid,cid)); 非常慢
delete from cate_links e where autoid !=(select min(autoid) as mid
from cate_links a where a.aid=e.aid and a.cid=e.cid); 错误
delete from cate_links e where autoid !=(select(select min(autoid)
from cate_links a where a.aid=e.aid and a.cid=e.cid) as tmp);
错误
delete from cate_links where autoid not in (select mid from (select
min(autoid) as mid from cate_links a group by concat(aid,cid))
b);是对的,很快
ALTER TABLE `cate_links` ADD UNIQUE `aid_2` ( `aid` , `cid`
);
show create table cate_links;

加载中…