MySQL严格模式下使用group by对结果去重报错的解决方法

1,153 阅读2分钟

「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战

前言

前面我在解决"only_full_group_by"sql模式下select 非聚合列和group by的冲突处理这个问题时,使用了any_value函数,我以为问题就这样解决了,在我回顾解决方法的时候,我又去看了下官方文档,然后想到一件事,这个函数在MySQL5.7.5才支持, 我们生产的数据库都是5.7以上吗?于是问了组长,组长说有5.6和5.7,我们需要避开对高版本特性的依赖,需要根据实际业务调用情况判断下能不能通过修改查询语句的方式避开,所以这个方法肯定又不行了。

新方案

仔细分析相关sql后,我发现只是使用group by 对指定的字段进项去重。

那么可以改成子查询

比如下面这个查询:

SELECT
    id,
    name,
    age,
    salary 
FROM
    emp 
GROUP BY age;

如果设置了sql模式为 ONLY_FULL_GROUP_BY,那么查询就会报错。

可以换成如下子查询:

SELECT
    id,
    name,
    age,
    salary 
FROM
    emp 
WHERE
    id IN ( SELECT min( id ) FROM emp GROUP BY age );

distinct也能对数据去重,但是distinct无法在查询所有列表的同时对数据去重

SELECT
distinct
    age
FROM
    emp ;

如果只对age去重,这样是没有问题的,但是如果想要查询其他列

SELECT
distinct
    age,
    name
FROM
    emp ;

就会根据age和name去重

总结

我们在使用数据库根据某个字段对数据去重时,可以使用group by,但是在sql_mode开启了ONLY_FULL_GROUP_BY模式下,如果select 列表包含非聚合列且不是group by列,就会报错。

对于MySQL5.7.5版本及以上的key使用any_value(列) as 列 这样的方式来解决,但是为了避开对高版本特性的依赖,兼容其他版本,不建议这么做,可以使用min或者max聚合函数获取分组后每个组的最小或者最大id,然后根据id查询。

还有一点就是如果没有group by ,select列表同时含有聚合列和非聚合列也会报错。