关于laravel中如何在where中使用in这回事

1 篇文章 0 订阅
1 篇文章 0 订阅

原因 

事情是这样的,新的项目中使用laravel作为开发框架,在使用查询构造器的时候就出现了这个问题。我在查询的时候需要使用 ,结果发现 下面这种使用方式是错误的,所以就花时间研究了一下。

$where[] = ['id','in',[1,2]];

官方给出的答案是使用:

whereIn()

我很不解,十分不解,所以就在网上搜了搜资料,有人指出如果想再where中使用in 可以使用这种方法:

$whereOr[] = [Db::Raw("id in (" . join(',',[1,2,3]) . ')'),1];

确实,这种方法是可以的,但是通过打印日志可以发现 这种方式最后出来的sql是有有问题的,它的sql是:

id in (1,2,3) = 1 

这种方式的sql 和传统的相比 效果是一致的。问题是这种sql是不走索引的,因为sql的where条件中是不允许出现表达式的。最后在网上实在找不到解决的办法,所以去查看了源码,where条件的源码如下:

 public function where($column, $operator = null, $value = null, $boolean = 'and')
    {
        //很明显当我们使用in 的时候是走了这里 我们进去addArrayOfWheres这个地方看一看
        if (is_array($column)) {
            return $this->addArrayOfWheres($column, $boolean);
        }

       
        [$value, $operator] = $this->prepareValueAndOperator(
            $value, $operator, func_num_args() === 2
        );

      
        if ($column instanceof Closure) {
            return $this->whereNested($column, $boolean);
        }

       
        if ($this->invalidOperator($operator)) {
            [$value, $operator] = [$operator, '='];
        }

        if ($value instanceof Closure) {
            return $this->whereSub($column, $operator, $value, $boolean);
        }

       
        if (is_null($value)) {
            return $this->whereNull($column, $boolean, $operator !== '=');
        }

        $type = 'Basic';

      
        if (Str::contains($column, '->') && is_bool($value)) {
            $value = new Expression($value ? 'true' : 'false');

            if (is_string($column)) {
                $type = 'JsonBoolean';
            }
        }

       

        if (! $value instanceof Expression) {
            $this->addBinding($value, 'where');
        }

        return $this;
    }

当我们的where 条件是下面这种方式的时候where 函数中会调用addArrayOfWheres 这个函数。

[
    ['id','=',1],
    ['status','in',[1,2,3]]
]

addArrayOfWheres 这个函数就是吧二维数组中每个数组的中的三个元素分别调用where函数。这样思路就很清晰了。当我们的['status','in',[1,2,3]] 作为元素执行到这里的时候会变成where('status','=',[1,2,3]) 这种方式调用where函数。但是where函数不可以这样使用,在laravel中in查新要使用whereIn 函数。所以我们们应该吧where函数改一改。

protected function addArrayOfWheres($column, $boolean, $method = 'where')
    {
        return $this->whereNested(function ($query) use ($column, $method, $boolean) {
            foreach ($column as $key => $value) {
                if (is_numeric($key) && is_array($value)) {
                    $query->{$method}(...array_values($value));
                } else {
                    $query->$method($key, '=', $value, $boolean);
                }
            }
        }, $boolean);
    }

至于如何修改where,我是这样改的:当$operator == ‘in’ 的时候调用whereIn ,经测试是可以的(注意 加入代码的位置,是放在if(is_array($column)))的后面。

 public function where($column, $operator = null, $value = null, $boolean = 'and')
    {
        // If the column is an array, we will assume it is an array of key-value pairs
        // and can add them each as a where clause. We will maintain the boolean we
        // received when the method was called and pass it into the nested where.
        if (is_array($column)) {
            return $this->addArrayOfWheres($column, $boolean);
        }

        if($operator === 'in'){
            return $this->whereIn($column,$value,$boolean);
        }

总结

想在where中使用in 查询 有两种办法:

1 缺点是无法使用索引

$whereOr[] = [Db::Raw("id in (" . join(',',[1,2,3]) . ')'),1];

2 需要修改源码,目前不知道会不会影响其他地方,如果有知道的大佬请留言,在此先感谢了!!

 修改位置在vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php  不同版本的laravel 可能位置不同,作者的版本是5.8的在604行加入

        if($operator === 'in'){
            return $this->whereIn($column,$value,$boolean);
        }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值