关于分组:技术分享-MySQL-分组需求探秘

6次阅读

共计 1780 个字符,预计需要花费 5 分钟才能阅读完成。

作者:刘晨

网名 bisal,具备十年以上的利用运维工作教训,目前次要从事数据库利用研发能力晋升方面的工作,Oracle ACE,领有 Oracle OCM & OCP、EXIN DevOps Master、SCJP 等国内认证,国内首批 Oracle YEP 成员,OCMU 成员,《DevOps 最佳实际》中文译者之一,CSDN & ITPub 专家博主,公众号 ”bisal 的集体杂货铺 ”,长期保持分享技术文章,屡次在线上和线下分享技术主题。

本文起源:原创投稿

* 爱可生开源社区出品,原创内容未经受权不得随便应用,转载请分割小编并注明起源。


前两天共事有个 MySQL 数据分组的需要,如下测试数据,须要找出每个 name 分组中 create_date 最近的记录:

须要留神的是,此处用的 MySQL 是 5.6,最后是应用这条语句:

select name, value, create_date, update_date from t1 group by name order by create_date desc;

查问后果如下,看着如同是对的,然而认真看下,就会发现其中的问题,例如 name=a 最近的 create_date 应该是 value=3 的记录,name=d 最近的 create_date 应该是 value=10 的记录:

用这条 SQL 失去的其实只是每个 name 分组中最先插入的记录,而后依照 create_date 进行了降序排列,和原始需要,齐全不同。

此时可采纳分而治之的策略,先做排序,再做分组:

select * from (select name, value, create_date, update_date from t1 order by create_date desc) t group by t.name;

即可失去原始需要的数据:

当然,针对此需要,可能有其余办法,有趣味的敌人,能够尝试写写,共享一下。

可能有仔细的敌人会发现个问题,就是上述 SQL 中的 group by,如同有些奇怪,如果依照惯例,select 中的字段须要呈现在 group by 中,上述语句居然没报错?

如果咱们在 MySQL 5.7 执行雷同的语句:

select name, value, create_date, update_date from t1 group by name order by create_date desc; 

就会提醒这个错:

如果是在 Oracle,则会提醒这个:

难道这是 MySQL 5.6 的个性?搜了一下,其实因为这个,在这套 5.6 的环境中,sql_mode 参数如下:

而在 5.7 中,sql_mode 参数如下,多了一个 ONLY_FULL_GROUP_BY,他的意思是“呈现在 SELECT 语句、HAVING 条件和 ORDER BY 语句中的列,必须是 GROUP BY 的列或者依赖于 GROUP BY 列的函数列”,这就不难解释,为什么 5.6 和 5.7 中景象是不同的,还是因为 5.7 默认对 SQL 格局校验的要求高了:

因而从 5.6 降级到 5.7,很可能呈现这种雷同的 SQL 执行后果不同的景象,这对兼容性测试的要求就会很高,究其原因,一方面是个性决定的,另一方面就是各种配置参数不同导致的。

能够在 5.7 的 sql_mode 中删除这个 ONLY_FULL_GROUP_BY,即可达到 5.6 雷同成果了,或者改写 SQL,例如:

select * from t1 a where create_date = (select max(create_date) from t1 b where a.name = b.name);

或者,

select * from t1 a where not exists (select * from t1 b where a.name = b.name and b.create_date > a.create_date);

MySQL 8.0 反对 row_number() 函数,操作应该和如下 Oracle 相近的。

Oracle 中能够应用 row_number() 实现此需要:

select * from (select name, create_date, row_number() over (partition by name order by create_date desc) as r from t1) where r=1;
正文完
 0