You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel中如何基于3个关联模型实现三层嵌套子查询?

两种现有写法的问题校验
  • 第一种写法存在两个核心错误:
    1. 筛选条件写反:需求是筛选delivered = true的关联记录,代码里写的是where('delivered', false),返回结果完全不符合预期
    2. 闭包内使用pluck():这个写法会先执行内层查询,把所有匹配的ID拉到PHP内存中再组装成数组传给外层查询,数据量大时会出现内存溢出问题,不属于数据库层面的嵌套子查询,性能很差
  • 第二种写法逻辑方向正确:
    1. delivered = true的筛选条件写对了,闭包内通过select()指定查询字段、直接构造查询逻辑,会生成数据库层面的嵌套子查询,不会提前加载数据到内存,性能正常
    2. 存在可维护性隐患:代码里硬编码了carts、accepted_carts表名,如果后续修改了模型绑定的表名、或者加了表前缀配置,这里会出现表名不匹配的错误,维护成本高
最佳实现方式

优先使用Laravel提供的关联查询whereHas实现,可读性、可维护性最好,性能和原生嵌套子查询一致:

  1. 先在对应模型中定义关联关系
// 在Transaction模型中定义和Cart的关联
public function carts()
{
    return $this->hasMany(Cart::class, 'transaction_id');
}

// 在Cart模型中定义和Acceptedcart的关联
public function acceptedCarts()
{
    return $this->hasMany(Acceptedcart::class, 'cart_id');
}
  1. 直接通过嵌套关联筛选数据
$transactions = Transaction::whereHas('carts.acceptedCarts', function ($query) {
    $query->where('delivered', true);
})->get();

如果不想定义模型关联,也要用动态获取表名的方式写嵌套子查询,避免硬编码表名的问题:

$transactions = Transaction::whereIn('id', function ($query) {
    $query->select('transaction_id')
        ->from((new Cart())->getTable())
        ->whereIn('id', function ($subquery) {
            $subquery->select('cart_id')
                ->from((new Acceptedcart())->getTable())
                ->where('delivered', true)
                ->distinct();
        })->distinct();
})->get();

注意:如果存在一个Cart对应多条Acceptedcart记录的场景,要在子查询中加distinct()去重,避免重复查询出同一条Transaction记录。

内容的提问来源于stack exchange,提问作者aref razavi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 14:33:29