Laravel多关联表查询:如何用单查询获取关联指定A所有B的C表记录
解决方案
核心思路
通过子查询获取目标A关联的所有B的ID集合,再通过BC表分组筛选出关联了全部这些B的C记录——利用分组后的计数等于B集合的总数来确保C关联了所有目标B,全程单次查询完成。
假设表结构
A表:主键idAB关联表:a_id(关联A)、b_id(关联B)B表:主键idBC关联表:b_id(关联B)、c_id(关联C)C表:主键id
方式1:使用查询构造器
$aId = 1; // 目标A记录的ID $cs = DB::table('c') ->join('bc', 'c.id', '=', 'bc.c_id') // 子查询获取目标A关联的所有B的ID ->whereIn('bc.b_id', function ($sub) use ($aId) { $sub->select('b_id') ->from('ab') ->where('a_id', $aId); }) ->groupBy('c.id', 'c.*') // 适配MySQL严格模式,需包含所有查询的C表字段 // 筛选出关联的B数量等于目标B总数的C ->havingRaw('COUNT(DISTINCT bc.b_id) = (SELECT COUNT(*) FROM ab WHERE a_id = ?)', [$aId]) ->get();
方式2:使用Eloquent模型(推荐,更贴合Laravel风格)
先确保模型已定义多对多关联:
// A模型 class A extends Model { public function bs() { return $this->belongsToMany(B::class, 'ab'); } } // B模型 class B extends Model { public function cs() { return $this->belongsToMany(C::class, 'bc'); } } // C模型 class C extends Model { public function bs() { return $this->belongsToMany(B::class, 'bc'); } }
然后执行查询:
$aId = 1; // 目标A记录的ID $cs = C::whereHas('bs', function ($query) use ($aId) { // 子查询限定只能是目标A关联的B $query->whereIn('b.id', function ($sub) use ($aId) { $sub->select('b_id') ->from('ab') ->where('a_id', $aId); }); }, '=', function ($countSub) use ($aId) { // 子查询获取目标A关联的B的总数 $countSub->select(DB::raw('COUNT(*)')) ->from('ab') ->where('a_id', $aId); })->get();
关键说明
- 用
COUNT(DISTINCT bc.b_id)避免BC表存在重复关联记录时的计数错误 - 全程通过子查询嵌套实现单次SQL执行,无需循环或多次查询
- 若MySQL关闭了
ONLY_FULL_GROUP_BY模式,查询构造器中的groupBy可简化为groupBy('c.id')
内容的提问来源于stack exchange,提问作者GEP1
相关产品推荐
相关产品推荐

