Laravel中使用union()关联模型时出现SQLSTATE[HY093]: Invalid parameter number错误的原因及解决办法
Laravel中使用union()关联模型时出现SQLSTATE[HY093]: Invalid parameter number错误的原因及解决办法
看起来你遇到的这个参数数量错误,大概率是Laravel 12对查询构建器的参数绑定逻辑做了更严格的校验,再加上你在关联方法里嵌套使用了union,导致参数计数混乱了。我来帮你拆解问题和对应的解决办法:
问题原因分析
- 关联查询的union参数冲突:你的
all_relation关联是基于part1和part2两个子查询的union,而这两个子查询本身又依赖于带嵌套关联的rel方法。当用with(['all_relation' => ...])加载这个关联时,Laravel的查询构建器在处理union的参数绑定时,会把两个子查询的参数合并,很容易出现重复计数或者参数不匹配的情况。 - Laravel版本升级的影响:从Laravel 10升级到12后,框架对参数绑定的校验变得更严格了——之前10版本可能容忍了这种参数计数的小问题,现在直接抛出了
HY093错误。
具体解决办法
办法一:改用访问器替代关联方法(最推荐)
把all_relation改成模型的访问器,绕开关联查询中union的参数绑定问题,逻辑更直观:
class MyModel extends Model { protected $table = 'table1'; use HasFactory; public function rel() { return $this->hasMany(MyModel2::class, 'rel_id', 'id')->with('next_relation'); } public function part1() { return $this->rel()->where('lvl', 1)->inRandomOrder()->take(8); } public function part2() { return $this->rel()->where('lvl', 2)->inRandomOrder()->take(2); } // 定义访问器,自动触发获取合并结果 public function getAllRelationAttribute() { $part1 = $this->part1()->get(); $part2 = $this->part2()->get(); // 合并后随机排序,和你之前的orderByRaw('RAND()')逻辑一致 return $part1->merge($part2)->shuffle(); } }
然后在控制器里直接访问属性即可,不需要再用with加载:
$result = MyModel::where('fv', '>', 0)->where('url', $url)->first(); // 直接访问生成的属性 dd($result->all_relation);
办法二:在控制器中直接合并结果
如果不想修改模型结构,也可以在控制器里分别加载两个关联,再手动合并:
$result = MyModel::with(['part1', 'part2']) ->where('fv', '>', 0) ->where('url', $url) ->first(); // 合并两个关联的结果并随机排序 $allRelation = $result->part1->merge($result->part2)->shuffle(); dd($allRelation);
办法三:手动处理union查询的参数绑定(进阶)
如果一定要保留关联形式,需要手动处理union的参数绑定,避免重复计数:
public function all_relation() { // 获取两个子查询的构建器实例 $part1Query = $this->part1()->getQuery(); $part2Query = $this->part2()->getQuery(); // 手动合并两个查询的绑定参数,避免重复 $combinedBindings = array_merge($part1Query->getBindings(), $part2Query->getBindings()); $unionQuery = $part1Query->union($part2Query)->setBindings($combinedBindings); // 基于union后的子查询构建关联 return $this->hasMany(MyModel2::class, 'rel_id', 'id') ->fromSub($unionQuery, 'table2') ->with('next_relation'); }
这个方法需要注意参数绑定的顺序,相对复杂,适合有特定关联需求的场景。
内容来源于stack exchange
相关产品推荐
相关产品推荐

