如何用LEFT JOIN实现关联表计数>1的SELECT查询?获取多字段关联非空分类
基础问题解答:LEFT JOIN + 关联表计数>1的SELECT查询
假设你有主表categories(分类表)和关联表products(产品表),要查询关联产品数量大于1的分类,基础SQL写法如下:
SELECT c.*, COUNT(p.id) AS product_count FROM categories c LEFT JOIN products p ON p.category_id = c.id GROUP BY c.id HAVING COUNT(p.id) > 1;
- 用
LEFT JOIN关联两张表,确保所有分类都被纳入查询,COUNT(p.id)统计的是关联的有效产品数(仅统计p.id不为空的记录) GROUP BY c.id按分类分组,保证每个分类只返回一条结果- 必须用
HAVING筛选聚合后的计数结果,WHERE在分组前执行,无法处理聚合值
实际场景解决方案:Laravel中筛选关联任意分类字段的非空分类
你当前的写法有明显问题:DB::select()返回的是原生查询结果数组,根本没法链式调用Eloquent的withCount()方法,会直接报错。另外你需要匹配产品表的category_root、category_parent、category_id三个字段与分类ID的关联,以下是两种可行方案:
方案1:Eloquent子查询(性能最优)
直接用whereExists判断分类是否存在关联产品(三个字段任意匹配即可):
$categories = Category::whereExists(function ($query) { $query->select(DB::raw(1)) ->from('products') ->whereRaw('products.category_root = categories.id OR products.category_parent = categories.id OR products.category_id = categories.id'); })->get();
方案2:原生SQL查询(适合复杂场景)
如果更习惯原生SQL,写法如下:
SELECT c.* FROM categories c WHERE EXISTS ( SELECT 1 FROM products p WHERE p.category_root = c.id OR p.category_parent = c.id OR p.category_id = c.id );
对应的Laravel调用:
$categories = DB::select('SELECT c.* FROM categories c WHERE EXISTS (SELECT 1 FROM products p WHERE p.category_root = c.id OR p.category_parent = c.id OR p.category_id = c.id)');
补充:同时统计关联产品数量
如果还要统计每个分类的关联产品总数(三个字段匹配的都算),可以在Category模型里定义自定义关联:
public function relatedProducts() { return $this->hasMany(Product::class) ->where(function ($query) { $query->where('category_root', $this->id) ->orWhere('category_parent', $this->id) ->orWhere('category_id', $this->id); }); }
然后查询时:
$categories = Category::withCount('relatedProducts') ->where('relatedProducts_count', '>', 0) ->get();
内容的提问来源于stack exchange,提问作者alex
相关产品推荐
相关产品推荐

