解决Mysql 分组去重并排序的问题

问题解决

假设我们现在有一张用户钱包表 该表包含着四个字段 气质ID字段是递增的 还有用户名(username), 货币数量(currency), 添加时间(addTime), 用户的货币数量随着时间的变化而更新

img

现在我们需要查询每个用户的最新货币数量,首先我们需要对列表进行排序并对用户去重,所以我们就简单的写了一条sql语句并执行:

1
select distinct username, currency, addTime from user_wallet order by addTime desc;

结果显示:

img

结果显示去重并未生效,在网上查看的资料后,其原因是distinct只能返回他的目标字段,而无法返回其他字段,所以我们使用group by 进行去重 在使用group by之前,由于我本地的MySQL 版本是5.7,而MySQL5.7 默认的 MySQL 配置中 sql_mode 配置了 only_full_group,需要 GROUP BY 中包含所有 在 SELECT 中出现的字段, 所以我们需要在MySQL 的配置中去掉这个配置:

在 配置文件(my.cnf)中 修改 sql_mode 的配置为:

1
2
$ vim /usr/local/etc/my.cnf
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

然后重启MYSQL服务即可:

img

结果显示,去重已经生效,但是排序未生效,这是因为我们是先去重拿到结果后再进行的排序,所以排序也是针对于去重后的结果进行排序,所以我们对这条Sql语句进行修改:

1
select username, currency, addTime FROM (select username, currency, addTime from user_wallet order by addTime DESC) alias GROUP BY username;

img

结果发现排序还是未能生效,

小编在查阅了相关资料后,发现在mysql 5.7 中 ,这种语法并没有效果,正确的写法是:

1
select username, currency, addTime FROM (select username, currency, addTime from user_wallet order by addTime DESC limit 0, 10000) alias GROUP BY username;

通过 explain 查看执行计划,可以看到没有 limit 的时候,少了一个 DERIVED 操作。DERIVED用于派生表的SELECT(FROM子句的子查询),所以没有它就相当于子句里的排序并没有被执行。至此问题解决

注意事项

  1. 采用子句查询时,别名(alias)不可少,会报语法错误
  2. 如果有分页,分页条件要写在子句里面
  3. 需要去重mysql的严格模式

参考文章

  1. Mysql5.7分组排序
  2. 解决MySQL:1055 - Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated
-------------本文结束感谢您的阅读-------------