Laravel查询报错SQLSTATE[42000]但生成的SQL在phpMyAdmin中可正常运行的问题咨询
解决Laravel GROUP BY 1055错误(SQL执行正常但Laravel报错)
这个问题的核心矛盾,是MySQL的ONLY_FULL_GROUP_BY SQL模式在Laravel和phpMyAdmin的执行环境中配置不一致导致的:
为什么会出现这种差异?
Laravel默认在数据库配置中开启了严格模式(包含ONLY_FULL_GROUP_BY规则),而你的phpMyAdmin连接的MySQL实例大概率没有开启这个模式:
- 当
ONLY_FULL_GROUP_BY开启时,MySQL会强制要求:SELECT语句中所有未被聚合函数处理的列,必须出现在GROUP BY子句中,否则直接抛出1055错误; - 当这个模式关闭时,MySQL会自动忽略这个限制,返回分组内该列的任意值,这就是你在phpMyAdmin里执行SQL能正常出结果的原因。
三种可行的解决方法
方法1:调整Laravel的数据库严格模式(最简单快捷)
打开项目根目录下的config/database.php,找到MySQL的配置块,通过修改strict参数或自定义modes来移除ONLY_FULL_GROUP_BY:
方案A:完全关闭严格模式(不推荐,会丢失其他严格校验能力)
'mysql' => [ // ...其他配置项 'strict' => false, ],
方案B:保留其他严格模式,仅移除ONLY_FULL_GROUP_BY(推荐)
'mysql' => [ // ...其他配置项 'strict' => true, 'modes' => [ 'STRICT_TRANS_TABLES', 'NO_ZERO_IN_DATE', 'NO_ZERO_DATE', 'ERROR_FOR_DIVISION_BY_ZERO', 'NO_ENGINE_SUBSTITUTION', ], ],
修改完成后,记得清除配置缓存:php artisan config:clear
方法2:修改查询语句,符合ONLY_FULL_GROUP_BY规则
把SELECT中所有未被聚合的列,全部添加到GROUP BY子句中。因为你用了makineler.*,所以需要把makineler表的所有字段、u.user_name、o.oyun_adi都加入分组:
$MakinelerQuery = Makineler::leftjoin('users as u','u.id','makineler.yetkilisi') ->leftjoin('oyunlar as o','o.id','makineler.oyun_id') ->leftjoin('sifre_hareket as sh','sh.makine_id','makineler.id'); $MakinelerQuery = $MakinelerQuery->select('makineler.*','u.user_name','o.oyun_adi'); $MakinelerQuery = $MakinelerQuery->selectRaw('max(sh.sifre_tarihi) as maxSifreTarihi'); // 将所有非聚合列加入GROUP BY $MakinelerQuery = $MakinelerQuery->groupBy( 'makineler.id', 'makineler.makine_adi', 'makineler.yetkilisi', 'makineler.oyun_id', // ...补充makineler表的其他字段 'u.user_name', 'o.oyun_adi' ); $fetchMakineler = $MakinelerQuery->get();
注意:如果makineler表字段较多,这种方法会比较繁琐,适合字段少的场景。
方法3:用ANY_VALUE()函数包裹非聚合列(适合需要保留严格模式的场景)
MySQL提供了ANY_VALUE()函数,用来明确告诉数据库:可以返回分组内该列的任意值,以此绕过ONLY_FULL_GROUP_BY的校验:
use Illuminate\Support\Facades\DB; $MakinelerQuery = Makineler::leftjoin('users as u','u.id','makineler.yetkilisi') ->leftjoin('oyunlar as o','o.id','makineler.oyun_id') ->leftjoin('sifre_hareket as sh','sh.makine_id','makineler.id'); // 用ANY_VALUE()处理非聚合列 $MakinelerQuery = $MakinelerQuery->select( DB::raw('makineler.*'), DB::raw('ANY_VALUE(u.user_name) as user_name'), DB::raw('ANY_VALUE(o.oyun_adi) as oyun_adi') ); $MakinelerQuery = $MakinelerQuery->selectRaw('max(sh.sifre_tarihi) as maxSifreTarihi'); $MakinelerQuery = $MakinelerQuery->groupBy('makineler.id'); $fetchMakineler = $MakinelerQuery->get();
总结
- 追求效率选方法1,想遵循严格SQL标准选方法2或3;
- 你可以在Laravel代码里执行
DB::select('SELECT @@sql_mode;'),再在phpMyAdmin里执行同样语句,对比结果就能直观看到两边的模式差异。
内容的提问来源于stack exchange,提问作者poison pawn
相关产品推荐
相关产品推荐

