在使用mysql排序的时候会想到按照降序分组来得到一组数据,而使用order by每每获得的不是理想中的结果,那么怎么才能使用group by 和order by获得理想中的数据结果呢?html
例如 有一个 帖子的回复表,posts( id , tid , subject , message , dateline ) ,mysql
id为 自动增加字段, tid为该回复的主题帖子的id(外键关联), subject 为回复标题, message 为回复内容, dateline 为回复时间,用UNIX 时间戳表示,sql
如今要求 选出 前十个来自不一样主题的最新回复post
SELECT * FROM posts GROUP BY tid LIMIT 10htm
这样一个sql语句选出来的并不是你想要的 最新的回复,而是最先的回复,其实是某篇主题的第一条回复记录!blog
也就是说 GROUP BY 语句没有排序,那么怎么才能让 GROUP 按照 dateline 倒序排列呢?加上 order by 子句?排序
看下面:索引
SELECT * FROM posts GROUP BY tid ORDER BY dateline DESC LIMIT 10class
这条语句选出来的结果和上面的彻底同样,不过把结果倒序排列了,而选择出来的每一条记录仍然是上面的记录,缘由是 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 * FROM (SELECT * FROM posts ORDER BY dateline DESC) as testbiao GROUP BY tid ORDER BY dateline DESC LIMIT 10