如何编写多条件Laravel模型及非原生实现orHaving子句
嘿,这两个问题我刚好熟得很,给你拆解一下!
一、如何编写带有多条件的Laravel模型?
Laravel处理多条件查询的方式特别灵活,最推荐的是用查询作用域来让代码更整洁、更易复用,当然也可以直接链式写查询,看你需求:
1. 全局作用域(自动生效的通用条件)
如果某个条件是所有查询都必须带上的,比如只查状态为「激活」的内容,就可以定义全局作用域:
class Post extends Model { protected static function booted() { static::addGlobalScope('active', function ($query) { $query->where('status', '=', 'active'); }); } }
这样每次调用Post::all()或者其他查询时,都会自动带上WHERE status = 'active'的条件,不用每次手动加。
2. 局部作用域(按需调用的特定条件)
如果是某个场景才需要的条件,就写局部作用域——方法名以scope开头,参数里带$query:
class Post extends Model { // 筛选指定分类+时间范围内的文章 public function scopeInCategoryAndDate($query, $categoryId, $start, $end) { return $query->where('category_id', $categoryId) ->whereBetween('published_at', [$start, $end]); } // 筛选评论数大于指定值的文章 public function scopeWithMoreComments($query, $minCount) { return $query->where('comment_count', '>', $minCount); } }
调用起来超简洁,还能链式组合:
// 查分类1、2023年发布且评论数>10的文章 $posts = Post::inCategoryAndDate(1, '2023-01-01', '2023-12-31') ->withMoreComments(10) ->get();
3. 直接链式写多条件(一次性场景)
如果只是临时用一次的查询,直接链式加条件就行,复杂的and/or组合用闭包分组:
// 基础多条件 $users = User::where('age', '>', 18) ->where('country', 'China') ->orWhere('is_vip', true) ->get(); // 复杂分组(active用户中,要么年龄>30要么是管理员) $users = User::where('status', 'active') ->where(function ($query) { $query->where('age', '>', 30) ->orWhere('role', 'admin'); }) ->get();
二、如何不用原生方式编写
orHaving子句? 你说的havingRaw确实是原生写法,但Laravel的查询构造器支持用闭包来分组having条件,和你写orWhere闭包的逻辑一模一样!
比如你原来的原生语句:
$model::havingRaw('(count > 10 and count <20) or (xxx and xxx)')
可以完全用Laravel的语法改写:
$model::select('*') ->having(function ($query) { // 第一个分组:count在10-20之间 $query->where(function ($subQuery) { $subQuery->having('count', '>', 10) ->having('count', '<', 20); }) // 用orHaving连接第二个分组 ->orHaving(function ($subQuery) { $subQuery->having('xxx', '=', '目标值') ->having('yyy', '>', '另一个值'); }); }) ->get();
这里的核心是:用闭包把and条件的having分组,然后用orHaving闭包连接另一个分组,完全不用写原生SQL字符串。
另外要注意,having通常是配合groupBy使用的,所以别忘了加上分组字段,比如:
$model::select('category', DB::raw('count(*) as count')) ->groupBy('category') ->having(function ($query) { $query->where(function ($sub) { $sub->having('count', '>', 10) ->having('count', '<', 20); }) ->orHaving(function ($sub) { $sub->having('category', '=', 'news') ->having('count', '>', 5); }); }) ->get();
内容的提问来源于stack exchange,提问作者allenartisan
相关产品推荐
相关产品推荐

