分组查询
原创2021年3月5日大约 3 分钟
1.启用MySQL的ONLY_FULL_GROUP_BY严格模式
启用MySQL的ONLY_FULL_GROUP_BY严格模式下要满足SELECT 字段的约束
否则sql直接报错,启用方式请参考官方文档,比较简单。
1.1 分组聚合的基本逻辑
GROUP BY 会将表中的数据按照指定列的值划分为多个组,每个组内的行具有相同的分组列值。聚合函数(如 COUNT、SUM、AVG 等)会针对每个分组内的数据进行计算。 例如:
SELECT customer_id, SUM(amount)
FROM orders
GROUP BY customer_id;
这里的 SUM(amount) 会计算每个 customer_id 分组内所有行的 amount 总和,而非整个表的 amount 总和
1.2 SELECT 字段的约束
- 分组列: SELECT 中的非聚合列必须是 GROUP BY 子句中指定的列,否则会导致错误
- 聚合函数: 所有未包含在 GROUP BY 中的列,必须通过聚合函数处理。例如 COUNT(*) 统计分组内的行数,MAX(column) 取分组内的最大值等
1.3 执行顺序
- WHERE 过滤原始数据
- GROUP BY 对过滤后的数据分组
- 聚合函数 对每个分组进行计算
- HAVING 对分组后的结果再次筛选
1.4 示例对比
场景 1:无 GROUP BY
SELECT SUM(amount) FROM orders;
结果:计算整个表的 amount 总和,所有记录视为一个组。
场景 2:有 GROUP BY
SELECT customer_id, SUM(amount)
FROM orders
GROUP BY customer_id;
结果:计算每个客户分组的 amount 总和,输出每个客户及其对应的总额
1.5 特殊情况与注意事项
- 空值处理:如果分组列包含 NULL 值,所有 NULL 会被归为同一组。
- 多列分组:若 GROUP BY 指定多个列(如 GROUP BY column1, column2),则仅当两列的值均相同时才会视为同一组。
- 聚合函数:聚合函数的结果是计算分组后的聚合值。
- 聚合函数嵌套:部分数据库(如 MySQL)不允许直接嵌套聚合函数(例如 SUM(AVG(column))),需通过子查询实现。
2 不启用MySQL的ONLY_FULL_GROUP_BY严格模式
本章节分析当不启用严格模式,并且sql刚好不遵守1.2章节的字段约束时查询结果。
示例sql如下:
SELECT customer_id, product_name, SUM(amount) FROM orders GROUP BY customer_id;
可能导致的结果:product_name的值可能来自分组中的任意一行(取决于存储引擎和索引),导致结果不确定性
3 总结建议
- 适用场景: 非严格模式适用于旧系统兼容、快速原型开发或明确接受数据不确定性的场景。 最佳实践:
- 如果实在要在严格模式下只给部分字段使用group by,可通过聚合函数(如ANY_VALUE())来给未分组字段随机取其中一行的值,而不是直接一刀切直接把Mysql这个限制去掉。
- 按需调整模式:若必须禁用严格模式,建议仅在会话级别临时关闭(SET SESSION sql_mode=...),而非全局永久禁用。
- 监控与测试:定期检查数据一致性,并在测试环境模拟严格模式以发现潜在问题