MySQL严格模式下GROUP BY分组报SQLSTATE[42000]错误不关闭严格模式解决咨询
问题原因
- MySQL严格模式默认开启
ONLY_FULL_GROUP_BY约束,要求GROUP BY子句中必须包含所有查询列表、排序条件里的非聚合字段,你的查询仅对digital_cards.id做分组,但是查询默认拉取了所有关联表的字段,且排序用到了companies.name,不符合该约束 - 原代码存在语法错误:
->groupBy('digital_cards.id');末尾多了分号,导致后续orderBy逻辑未被正确拼接进查询语句
解决方案
方案1:使用whereExists替代join服务表(优先推荐,完全避免分组,性能更优)
你需要分组的本质原因是关联服务表后,同一张数字卡会因为匹配多个服务产生重复数据,用whereExists可以避免产生重复数据,不需要分组即可实现需求:
$cards = DB::table('digital_cards') ->join('companies', 'digital_cards.company_id', '=', 'companies.id') ->join('profiles' , 'digital_cards.profile_id', '=', 'profiles.id') ->where('digital_cards.is_public', '=', 1) ->whereExists(function ($query) use ($keyword) { $query->select(DB::raw(1)) ->from('company_services') ->join('services', 'company_services.service_id', '=', 'services.id') ->whereColumn('company_services.company_id', 'companies.id') ->where('services.service', 'LIKE', "%{$keyword}%"); }) ->orderBy('companies.name', 'ASC') ->paginate(10);
方案2:调整GROUP BY规则适配严格模式
如果必须保留分组的写法,明确指定查询字段,把需要用到的非聚合字段都加到GROUP BY中:
$cards = DB::table('digital_cards') ->select('digital_cards.*', 'companies.name as company_name', 'profiles.*') // 明确指定需要的字段 ->join('companies', 'digital_cards.company_id', '=', 'companies.id') ->join('profiles' , 'digital_cards.profile_id', '=', 'profiles.id') ->join('company_services', 'companies.id', '=', 'company_services.company_id') ->join('services', 'company_services.service_id', '=', 'services.id') ->where('services.service', 'LIKE', "%{$keyword}%") ->where('digital_cards.is_public', '=', 1) ->groupBy(['digital_cards.id', 'companies.name', 'profiles.id']) // 加入所有非聚合查询、排序字段 ->orderBy('companies.name', 'ASC') ->paginate(10);
方案3:使用ANY_VALUE包裹非分组字段
如果部分字段不需要保证唯一值,可以用MySQL内置的ANY_VALUE()函数包裹不需要分组的字段,适配严格模式:
$cards = DB::table('digital_cards') ->select('digital_cards.*', DB::raw('ANY_VALUE(companies.name) as company_name'), DB::raw('ANY_VALUE(profiles.name) as profile_name')) ->join('companies', 'digital_cards.company_id', '=', 'companies.id') ->join('profiles' , 'digital_cards.profile_id', '=', 'profiles.id') ->join('company_services', 'companies.id', '=', 'company_services.company_id') ->join('services', 'company_services.service_id', '=', 'services.id') ->where('services.service', 'LIKE', "%{$keyword}%") ->where('digital_cards.is_public', '=', 1) ->groupBy('digital_cards.id') ->orderByRaw('ANY_VALUE(companies.name) ASC') ->paginate(10);
内容的提问来源于stack exchange,提问作者Cesar Osuna
相关产品推荐
相关产品推荐

