Laravel Query Builder多表查询问题:原生SQL正常但构建器结果异常
解决Laravel Query Builder分组后结果不符合预期的问题
我来帮你梳理下问题所在,以及对应的解决办法~
首先咱们先明确你的核心需求:每个用户对应多条保单,你想获取每个用户对应的最新last_operation值对吧?你的原生SQL虽然能运行,但其实在数据库开启ONLY_FULL_GROUP_BY严格模式的情况下,它是会报错的——因为SELECT里的last_operation既不在GROUP BY子句中,也没有使用聚合函数,数据库只能随机返回该用户某条保单的last_operation,这就是你的Query Builder写法结果不符合预期的核心原因。
下面给你两种靠谱的解决方案,你可以根据实际场景选择:
方案1:用聚合函数获取最新操作(适合last_operation是时间类型的场景)
如果last_operation是存储操作时间的字段,直接用MAX()聚合函数就能拿到每个用户的最新操作时间:
$lastOperationUser = DB::table('policies') ->join('users', 'users.id', '=', 'policies.user_id') ->select( 'users.id as user_id', DB::raw('MAX(policies.last_operation) as last_operation') ) ->groupBy('users.id');
方案2:关联子查询获取最新保单的操作(适合需精准取最新一条保单的场景)
如果last_operation不是时间,或者你需要的是每个用户最新创建的那条保单对应的last_operation(比如按保单ID排序取最新),可以先通过子查询找到每个用户的最新保单ID,再关联原表获取对应字段:
// 先获取每个用户的最新保单ID $latestPolicies = DB::table('policies') ->select('user_id', DB::raw('MAX(id) as latest_policy_id')) ->groupBy('user_id'); // 关联子查询拿到对应的last_operation $lastOperationUser = DB::table('policies') ->joinSub($latestPolicies, 'latest_policies', function ($join) { $join->on('policies.id', '=', 'latest_policies.latest_policy_id'); }) ->join('users', 'users.id', '=', 'policies.user_id') ->select('users.id as user_id', 'policies.last_operation');
为什么原来的写法不对?
你原来的Query Builder写法中,select('last_operation','user_id')然后groupBy('user_id'),在严格模式下会直接报错;如果数据库没开严格模式,数据库会随机返回该用户任意一条保单的last_operation,这完全不可靠,结果自然不符合预期。你的原生SQL其实也存在同样的问题,只是刚好在你的数据库环境下返回了看似正确的结果而已。
内容的提问来源于stack exchange,提问作者user3892232
相关产品推荐
相关产品推荐

