Laravel GroupBy查询在MySQL正常运行但MariaDB报错且无权限修改sql_mode
MariaDB 10.1环境下Laravel分组查询1055报错兼容方案
报错核心逻辑
- MariaDB 10.1+默认启用
ONLY_FULL_GROUP_BY校验,要求SELECT子句内所有非聚合、未纳入GROUP BY规则的字段,必须可被分组键唯一确定,否则抛出1055权限/语法违反错误 - 托管环境下无超级权限,无法修改全局sql_mode配置;原有业务逻辑的分组规则为“按项目ID分组合并关联位置名称”,同一项目ID下的项目基础字段(如名称)天然唯一,与本地MySQL5.7的运行逻辑完全一致
- 报错日志中出现的精简版SQL(无group_concat关联字段),是Laravel
paginate()方法自动生成分页计数查询时的逻辑缺陷触发,并非主业务查询本身的语法错误
零侵入兼容方案(无需逐列追加GROUP BY字段)
方案1:会话级临时调整当前连接的校验规则
- 无需全局权限,仅对当前数据库连接生效,完全不改动原有业务查询代码
- 实现位置可放置在
app/Providers/AppServiceProvider.php的boot()方法中,应用启动时对当前数据库连接执行一次会话配置:
// 移除当前会话的ONLY_FULL_GROUP_BY校验,保留其余原有sql_mode规则 DB::statement("SET SESSION sql_mode = (SELECT REPLACE(@@SESSION.sql_mode, 'ONLY_FULL_GROUP_BY', ''))");
- 该配置仅作用于当前PHP-FPM进程对应的数据库连接,连接释放后自动失效,不会影响数据库全局配置,普通数据库用户权限即可执行该语句
方案2:使用ANY_VALUE()函数包裹分组内的唯一确定字段
- 该函数是MySQL/MariaDB原生提供的兼容函数,对分组内可确定唯一值的字段,自动取同组任意值返回,与本地MySQL5.7的运行行为完全一致
- 仅需修改原有selectRaw语句,无需向groupBy追加任何字段:
->selectRaw(' v2_projects.id, ANY_VALUE(v2_projects.name) as name, group_concat(v2l.name) as locations ')
- 该写法完全符合
ONLY_FULL_GROUP_BY的校验规则,不会触发1055报错,后续新增基础字段时,仅需对非分组键、非聚合的字段统一用ANY_VALUE包裹即可,维护成本远低于逐字段加GROUP BY
方案3:修正分页逻辑的计数查询缺陷
- 报错日志中的精简SQL,本质是Laravel分页组件自动生成的count查询未正确继承原查询的select结构,导致分组校验不匹配
- 手动指定分页的计数逻辑,跳过自动生成的错误SQL:
// 替换原有 groupBy 后直接paginate的写法 $projects = $projects->groupBy('v2_projects.id')->paginate( 10, ['v2_projects.id', 'v2_projects.name'], 'page', null, function () use ($projects) { // 基于原查询条件,对项目ID做去重计数,避开有问题的自动分组查询 return $projects->clone()->countDistinct('v2_projects.id'); } );
不推荐逐列追加GROUP BY字段的实现方式:该方式维护成本高,后续新增查询字段时需要反复调整分组规则,极易因遗漏字段触发新的1055报错
内容的提问来源于stack exchange,提问作者Mustafa Poya
相关产品推荐
相关产品推荐

