Laravel中能否将三个SELECT查询合并为一个查询?
可以合并!两种方案帮你搞定
当然能把这三个查询合并成一个——而且还能优雅处理空结果的情况,具体分两种场景来实现:
方案一:利用Eloquent关联(推荐,更符合Laravel风格)
首先得确保你的三个模型之间已经定义了正确的关联关系(如果还没定义,先补上):
1. 定义模型关联
在Category模型中添加关联:
public function subcategories() { // 第二个参数是Subcategory表中关联Category的外键,对应你原查询里的`sub_id` return $this->hasMany(Subcategory::class, 'sub_id'); }
在Subcategory模型中添加关联:
public function subsubcategories() { // 同理,这里的外键是SubSubcategory表中关联Subcategory的`subsub_id` return $this->hasMany(SubSubcategory::class, 'subsub_id'); }
2. 合并查询并筛选
通过嵌套预加载with(),可以一次性拉取所有关联数据,同时带上你的筛选条件:
$categoryTree = Category::where('cat_id', $mainCatId) ->with([ // 筛选指定的子分类 'subcategories' => function ($query) use ($catId) { $query->where('sub_id', $catId) ->select(['subcat_id', 'subcategory_name', 'sub_id']); // 必须包含外键`sub_id`,否则Eloquent无法关联 }, // 筛选指定的子子分类 'subcategories.subsubcategories' => function ($query) use ($subCatId) { $query->where('subsub_id', $subCatId) ->select(['subsubcat_id', 'subsubcategory_name', 'subsub_id']); // 同样要包含外键 } ]) ->select(['cat_id', 'category_name']) ->first(); // 按cat_id查询应该只有一条结果,用first比get更高效
空结果处理
- 如果主分类不存在,
$categoryTree会是null,可以用optional($categoryTree)或者简单的if判断来避免报错。 - 如果子分类/子子分类为空,对应的属性会是一个空集合
Collection,直接遍历也不会出问题。
方案二:使用原生Join查询(适合需要扁平结构的场景)
如果不想定义模型关联,或者需要扁平的数据集,可以用DB门面的leftJoin来合并查询,同时保证空结果不会导致整个查询返回空:
$combinedData = DB::table('categories') // Left Join保证即使子分类为空,主分类数据依然返回 ->leftJoin('subcategories', function ($join) use ($catId) { $join->on('categories.cat_id', '=', 'subcategories.sub_id') ->where('subcategories.sub_id', '=', $catId); }) // 同理,Left Join处理子子分类的空结果 ->leftJoin('subsubcategories', function ($join) use ($subCatId) { $join->on('subcategories.subcat_id', '=', 'subsubcategories.subsub_id') ->where('subsubcategories.subsub_id', '=', $subCatId); }) ->where('categories.cat_id', '=', $mainCatId) ->select( 'categories.cat_id', 'categories.category_name', 'subcategories.subcat_id', 'subcategories.subcategory_name', 'subsubcategories.subsubcat_id', 'subsubcategories.subsubcategory_name' ) ->get();
这种方式返回的是扁平的数组/对象,某一层没有数据时,对应的字段会是null,不会丢失上层的有效数据。
内容的提问来源于stack exchange,提问作者Kiow
相关产品推荐
相关产品推荐

