【问题标题】:Laravel: WHERE(...) AND ( cond1 OR cond2 ...) always creates AND conditionLaravel:WHERE(...) AND ( cond1 OR cond2 ...) 总是创建 AND 条件
【发布时间】:2019-08-26 19:18:27
【问题描述】:

我已经多次将查询对象传递给子函数,没有任何问题。但是,当我想要 OR 关系时,查询生成器非常强迫症,总是给我 AND!

业务逻辑site_id = $site_id AND (cond1 OR cond2 OR ..) cond1..n 取自$cols 任意匹配$search

$cols = "priority, status, name, actionType"

$search 是要搜索的字符串,在这种情况下:Medium

这里的问题是不是缺少的列,这是为了创建错误以吐出 SQL。如何让 Laravel 使用 orWhere 和括号正常运行的问题。

第一种方法:

$data = $this->where('site_id', $site_id) ;
$data = $this->search($cols, $orderBy, $search, $data) ;

第二种方法(搜索(...)):

    $searches = explode(',', $col);

    $len = sizeof($searches) ;

    if ($len > 0) {
      for ($i=0; $i < $len ; $i++) {
        $val = trim($searches[$i]) ;

        $data->where(function ($query) use ($val, $search, $data) {
          $query->orWhere(function ($query1) use ($val, $search, $data) {
          $query1->orWhereRaw("$val LIKE '%$search%'");
        }) ;
      }) ;
    }  // for
   }  // if

我特意留下一个未知的列来查看 Laravel 生成的 SQL:

Unknown column 'name' in 'where clause' (SQL: select count(*) as aggregate from `actions` where `site_id` = 555 and ((priority LIKE '%Medium%')) and ((status LIKE '%Medium%')) and ((name LIKE '%Medium%')) and ((actionType LIKE '%Medium%')))

如您所见,尽管有多个 orWhere's I 仍然得到 AND!因为第二种方法在基础模型中,它是为所有查询而设计的,我试图避免过多的重复搜索功能。

SQL 几乎就是我想要的。

如果我省略以下代码:

//        $data->where(function ($query) use ($val, $search, $data) {
          $data->orWhere(function ($query1) use ($val, $search, $data) {
          $query1->orWhereRaw("$val LIKE '%$search%'");
        }) ;
//      }) ;

结果为:

Unknown column 'name' in 'where clause' (SQL: select count(*) as aggregate from `actions` where `site_id` = 555 or (priority LIKE '%Medium%') or (status LIKE '%Medium%') or (name LIKE '%Medium%') or (actionType LIKE '%Medium%')

【问题讨论】:

    标签: php laravel laravel-5 eloquent


    【解决方案1】:

    在您的代码中编辑查询

    $data = $this->where('site_id', $site_id) ; // where `site_id` = 555
    
    $searches = explode(',', $col);
    
    $len = sizeof($searches) ;
    
    if ($len > 0) {
            $data->where(function ($query) use ($search, $len, $searches) // AND
            {
                for ($i=0; $i < $len ; $i++) {
                    $val = trim($searches[$i]) ;
    
                    $query->orWhereRaw("$val LIKE '%$search%'"); //  (priority LIKE '%Medium%' or status LIKE '%Medium%' or name LIKE '%Medium%' or actionType LIKE '%Medium%')
                }
            });
        }
    
        dd($data->toSql());
    

    【讨论】:

    • 感谢 Ruchi,但我从那个查询中得到了这个 SQL:select count(*) as aggregate from actions where site_id = 555 and priority, status, actionType, summary LIKE %%)跨度>
    【解决方案2】:

    拥有两个where() 调用将始终创建一个AND。 拥有一个where() 和一个orWhere() 将产生一个OR

    所以要么这样做:

    $data = $this->search($cols, $orderBy, $search, $data) ;
    $data = $this->orWhere('site_id', $site_id) ;
    

    或者这个:

        $searches = explode(',', $col);
    
        $len = sizeof($searches) ;
    
        if ($len > 0) {
          for ($i=0; $i < $len ; $i++) {
            $val = trim($searches[$i]) ;
    
            $data->orWhere(function ($query) use ($val, $search, $data) {
              $query->orWhere(function ($query1) use ($val, $search, $data) {
              $query1->orWhereRaw("$val LIKE '%$search%'");
            }) ;
          }) ;
    

    编辑:重新阅读您的问题和评论后,我认为您正在寻找一个额外的 where() 包装 for-looped orWhere() 调用。像这样的:

        $searches = explode(',', $col);
    
        $len = sizeof($searches) ;
    
        if ($len > 0) {
    
          $data->where(function ($query) use ($val, $search, $data) {
            for ($i=0; $i < $len ; $i++) {
              $val = trim($searches[$i]) ;
    
              $data->orWhere(function ($query) use ($val, $search, $data) {
                $query->orWhere(function ($query1) use ($val, $search, $data) {
                $query1->orWhereRaw("$val LIKE '%$search%'");
              }) ;
            }) ;
          }) ;
    

    【讨论】:

    • 感谢@PtrTon,我仍然得到 site_id=XXX 和子条件之间的 OR。应该是site_id=XXX and (cond1 OR cond2 ...)。我仍然得到这个:select count(*) as aggregate from `actions` where `site_id` = 555 or ((priority LIKE '%Medium%')) or ((status LIKE '%Medium%')) or ((name LIKE '%Medium%')) or ((actionType LIKE '%Medium%')) 我想要评估第一个条件site_id=XXX 的原因是出于性能原因,因为这会减少第二个条件评估的数据集。
    • 我想我理解你现在遇到的问题,我已经更新了我的答案。你能再看看吗?
    • 刚刚实现了 - 伟大的思想都一样!但是,没有香蕉:``` select count(*) as aggregate from actions where site_id = 555 and priority, status, actionType, summary LIKE %%) ```
    猜你喜欢
    • 1970-01-01
    • 2010-12-12
    • 2013-03-27
    • 1970-01-01
    • 2013-11-09
    • 1970-01-01
    • 1970-01-01
    • 2016-04-24
    • 2013-04-07
    相关资源
    最近更新 更多