起因

在MySQL的SQL查询中,GROUP BY语句用于将结果集按照一个或多个列进行分组。早期MySQL版本对GROUP BY的实现较为宽松,允许在SELECT列表中出现未包含在GROUP BY子句中的列,且这些列的值未必唯一或确定。这种宽松的行为可能导致查询结果不可预测,尤其是在分布式或高并发环境下,容易引发数据一致性问题。

为了解决这一隐患,MySQL引入了ONLY_FULL_GROUP_BY SQL模式。该模式要求SELECT列表、HAVINGORDER BY等子句中出现的所有列,要么是GROUP BY子句中的分组列,要么是聚合函数的结果。这样可以保证查询结果的确定性和一致性。

适用场景

  • 数据一致性要求高的场景:如金融、统计等对数据准确性要求极高的业务。
  • 团队开发规范统一:避免因不同开发者对SQL语法理解不同而导致的潜在Bug。
  • 迁移到其他数据库:如PostgreSQL等数据库本身就强制要求GROUP BY列的完整性,提前适应有助于迁移。

MySQL版本要求

  • MySQL 5.7.5及以上版本,ONLY_FULL_GROUP_BY默认开启。
  • MySQL 5.6及以下版本,默认未开启,需要手动设置。

如何开启或关闭

可以通过如下方式查看当前SQL模式:

SELECT @@sql_mode;

开启ONLY_FULL_GROUP_BY

SET sql_mode = 'ONLY_FULL_GROUP_BY';

关闭ONLY_FULL_GROUP_BY(不推荐):

SET sql_mode = '';

案例与示例代码

1. 未开启ONLY_FULL_GROUP_BY时的查询

假设有如下表结构和数据:

CREATE TABLE sales (
  id INT PRIMARY KEY,
  product VARCHAR(50),
  amount INT
);

INSERT INTO sales VALUES
(1, 'A', 100),
(2, 'A', 200),
(3, 'B', 150);

查询每种产品的任意一条销售记录:

SELECT product, amount FROM sales GROUP BY product;

结果(未开启ONLY_FULL_GROUP_BY时):

productamount
A100
B150

此时amount列的值是任意一条属于该分组的记录,结果不确定。

2. 开启ONLY_FULL_GROUP_BY后的行为

开启后,执行上述SQL会报错:

ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'sales.amount' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

3. 正确写法

应使用聚合函数:

SELECT product, SUM(amount) AS total_amount FROM sales GROUP BY product;

结果:

producttotal_amount
A300
B150

或者:

SELECT product, MAX(amount) AS max_amount FROM sales GROUP BY product;

总结

  • ONLY_FULL_GROUP_BY提升了SQL查询的规范性和结果的确定性。
  • 建议在生产环境中开启,避免潜在的数据一致性问题。
  • 编写SQL时,务必保证SELECT列表中的非聚合列都包含在GROUP BY中,或使用聚合函数。

希望本文能帮助你理解ONLY_FULL_GROUP_BY的由来、适用场景、版本要求及正确用法。

分类: MySQL 标签: MySQLONLY_FULL_GROUP_BY

评论

暂无评论数据

暂无评论数据

目录