MySQL中 ONLY_FULL_GROUP_BY 的详解
起因
在MySQL的SQL查询中,GROUP BY
语句用于将结果集按照一个或多个列进行分组。早期MySQL版本对GROUP BY
的实现较为宽松,允许在SELECT
列表中出现未包含在GROUP BY
子句中的列,且这些列的值未必唯一或确定。这种宽松的行为可能导致查询结果不可预测,尤其是在分布式或高并发环境下,容易引发数据一致性问题。
为了解决这一隐患,MySQL引入了ONLY_FULL_GROUP_BY
SQL模式。该模式要求SELECT
列表、HAVING
、ORDER 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
时):
product | amount |
---|---|
A | 100 |
B | 150 |
此时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;
结果:
product | total_amount |
---|---|
A | 300 |
B | 150 |
或者:
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
版权申明
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据