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

如何编写多条件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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:35:32