Laravel 使用 MySQL 的 ONLY_FULL_GROUP_BY 问题
定位问题
最近在使用 Laravel Relationship 查询关联模型时遇到了如下错误:
SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #6 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'echo_dev.domain_links.domain_id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
相关的表结构如下:
keywords:
- id
articles:
- id
- category_id
articles_keywords:
- article_id
- keyword_id
- category_id
调用方式:
$category->keywords()->groupBy('articles_keywords.keyword_id');
关联表中的 keyword_id 有重复的情况,所以使用了 groupBy 来去重,结果出现了上面的错误,大意是 ONLY_FULL_GROUP_BY
的查询模式要求 SELECT 的字段必须全部出现在 GROUP BY 中,这是因为 5.7 之后 Mysql 的 查询模式有所变化,默认值如下:
ONLY_FULL_GROUP_BY
STRICT_TRANS_TABLES
NO_ZERO_IN_DATE
NO_ZERO_DATE
ERROR_FOR_DIVISION_BY_ZERO
NO_AUTO_CREATE_USER
NO_ENGINE_SUBSTITUTION
关于这些模式的作用,可以查阅 MySQL 官方文档
解决方法
以 Laravel 5.4 为例,如果要解决这个问题,可以找到 Laravel 的配置文件 database.php,修改如下部分:
'connections' => [
'mysql' => [
'strict' => true
//默认值,表示使用 5.7 的默认模式。
'strict' => false
//表示使用 5.6 的默认模式。
]
]
如果需要显式指定 sql_mode,可以如下设置:
'connections' => [
'mysql' => [
//忽略该值,根据 strict 值确定查询模式
'modes' => null,
//禁用所有模式
'modes' => [],
//显示指定模式
'modes' => [
'STRICT_TRANS_TABLES',
'ONLY_FULL_GROUP_BY',
],
]
]
也可以通过 SQL 语句来修改 sql_model
SET sql_mode = '';
SET sql_mode = 'ONLY_FULL_GROUP_BY';
需要注意的是,这种方式在 MySQL 重启后会失效,如果需要永久生效,请修改 MySQL 的配置文件。