背景
使用ThinkPHP 8框架,遇到了一个1055异常错误。错误是由数据库查询引起的,具体来说是因为MySQL的一个特性——only_full_group_by
设置导致的
场景
正在本地环境中执行一条命令:
➜ code git:(main) ✗ php think scan test -vvv
这条命令用于执行一个详细的测试案例,但是它触发了一个异常:
[think\db\exception\PDOException]
SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #1 of SELECT
list is not in GROUP BY clause and contains nonaggregated column 'qscan.sast_cod
eql.id' which is not functionally dependent on columns in GROUP BY clause; this
is incompatible with sql_mode=only_full_group_by
显然,这个错误与SQL语句中的GROUP BY
子句有关,因为某些列没有被包含在GROUP BY
中,而这些列又不是聚合函数的一部分,这就与数据库服务器的only_full_group_by
模式不兼容了。
修复原理
在MySQL中,only_full_group_by
是一个SQL模式设置,它要求所有的非聚合列都必须出现在GROUP BY
子句中,否则查询将失败。如果我们的应用程序依赖于旧的行为(即允许不完全的GROUP BY
),我们需要禁用这个设置或修改查询来满足新规则。
实践测试
为了解决这个问题,我们首先尝试临时更改数据库的SQL模式。可以在MySQL命令行工具中执行如下命令:
SET sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
这会临时去掉only_full_group_by
设置的影响。为了在ThinkPHP 8中实现同样的行为,可以使用框架提供的数据库操作方法来执行这个设置:
Db::connect('local_test')->execute("SET sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));");
这样做的好处是可以在代码层面控制SQL模式,而不是全局地改变数据库的配置。这种方法更适合在测试环境或者调试阶段使用,确保我们不会影响生产环境的数据库设置。
总结
虽然通过上述方法可以解决眼前的问题,但长期来看,我们应该调整查询逻辑,使其符合现代数据库的最佳实践。例如,我们可以确保所有非聚合列都被正确地包含在GROUP BY
子句中,或者添加必要的聚合函数。此外,还可以考虑使用更灵活的SQL模式设置,比如STRICT_TRANS_TABLES
,它允许部分GROUP BY
,但仍然保持了一定程度的数据完整性检查。
编写查询时要考虑到only_full_group_by
设置,以避免将来再次遇到类似问题。
作者: 汤青松
日期:2024年8月22日
微信:songboy8888
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。