如何在Laravel查询中将子查询结果存入变量以用于后续计算?
问题原因分析
- MySQL自定义变量的执行顺序不保证:同一条SELECT语句中,变量赋值和读取的先后顺序没有官方约定,你在同一SELECT中刚给
@variable赋值就直接调用,大概率读取到的是赋值前的空值,所以final_amount返回空 - 变量未初始化:Laravel默认不会预定义SQL会话变量,首次执行该查询时
@variable本身就不存在,计算逻辑自然失效 - 分组逻辑不符合SQL规范:你当前
groupBy('job.id')但SELECT中包含了未聚合的user.id、user.name字段,开启MySQL严格模式时会直接抛出语法错误
可行解决方案
方案1:直接复用聚合逻辑(最推荐)
完全没必要在SQL里声明自定义变量,直接把统计逻辑套用到final_amount的计算中即可,逻辑清晰且不会出现顺序问题:
$result = DB::table('user') ->select( DB::raw("user.id, user.name, COUNT(DISTINCT job.total_cost) AS total_cost, COUNT(DISTINCT job.total_cost) * 2.3 as final_amount ")) ->leftJoin('job','job.code','user.id') ->groupBy('user.id', 'user.name', 'job.id') // 调整分组符合SQL规范 ->get();
方案2:查询后在PHP侧处理变量
如果你需要把total_cost的值存为PHP变量供后续多逻辑复用,可以直接操作查询返回的集合:
$result = DB::table('user') ->select( DB::raw("user.id, user.name, COUNT(DISTINCT job.total_cost) AS total_cost ")) ->leftJoin('job','job.code','user.id') ->groupBy('user.id', 'user.name', 'job.id') ->get() ->map(function ($item) { // 这里可以把total_cost赋值给变量做任意计算 $totalCost = $item->total_cost; $item->final_amount = $totalCost * 2.3; // 其他后续计算逻辑可以直接加在这里 return $item; });
方案3:必须用SQL变量的修正写法
如果业务场景要求必须在SQL中使用变量,需要先初始化变量,再拆分子查询保证赋值顺序在读取之前:
// 先初始化会话变量 DB::statement('SET @variable := 0'); $result = DB::table('user') ->select( DB::raw("user.id, user.name, total_cost, @variable * 2.3 as final_amount"), ) ->fromSub(function ($query) { $query->from('user') ->selectRaw("user.id, user.name, COUNT(DISTINCT job.total_cost) AS total_cost, @variable := COUNT(DISTINCT job.total_cost)") ->leftJoin('job','job.code','user.id') ->groupBy('user.id', 'user.name', 'job.id'); }, 't') ->get();
内容的提问来源于stack exchange,提问作者Prince Paraste
相关产品推荐
相关产品推荐

