在 Codeigniter 中对 WHERE 子句进行分组

Posted

技术标签:

【中文标题】在 Codeigniter 中对 WHERE 子句进行分组【英文标题】:Grouping WHERE clauses in Codeigniter 【发布时间】:2011-09-22 03:39:30 【问题描述】:

我想在 Codeigniter 中使用 Active Records 生成以下 SQL 代码:

WHERE name != 'Joe' AND (age < 69 OR id > 50)

执行以下操作似乎是尽我所能,我不知道如何对它们进行分组

$this->db->select()->from('users')->where('name !=', 'Joe')->where('age <', 69)->or_where('id <', $id); 

有什么想法吗?我的 SQL 查询太复杂,所以我不想用传统 SQL 重写所有内容。

更新

My SQL 代码是根据传递给模型方法的某些参数的值动态生成的。不能使用括号的问题会导致问题,因为运算符的优先级使得ANDOR 之前首先被评估。

*这是我的一段活动记录代码,前后还有一些其他代码:

            ... some $this->db->where() ...
            ... some $this->db->where() ...

    if($price_range) 
        $price_array = explode('.', $price_range);
        for($i = 0; $i < count($price_array); $i++) 
            if($i == 0) 
                $this->db->where('places.price_range', $price_array[$i]);
             else 
                $this->db->or_where('places.price_range', $price_array[$i]);
            
        

    

            ... some $this->db->where() ...
            ... some $this->db->where() ...

问题出现是因为我使用了$this-&gt;db-&gt;or_where(),它引入了一个OR 子句,该子句将运算符优先级置于混乱状态,而无法使用( ) 更改顺序。

** 有没有办法解决这个问题? **

【问题讨论】:

它似乎不太复杂,不能让你用普通 SQL 编写它 @yes123:上面的例子只是一个例子,仅我的活动记录就产生了多达60多行动态生成的实际SQL代码,其中许多是条件SQL语句。 这是 Codeigniter 中 Activerecord 类的不幸限制。 @timw4mail:有什么建议吗?用纯 SQL 重写所有内容的任何替代方法? @Nyxynyx 最好的方法可能是将 where 子句作为纯 sql 字符串执行。 $this->db->where() 方法可以采用纯字符串。 【参考方案1】:

你可以使用一个大字符串。

$this->db->select()->from('users')->where("name != 'Joe' AND (age < 69 OR id > 50) ");

【讨论】:

我已经用我项目中的一些实际代码更新了原始问题...如您所见,我不能像您在回答中那样使用括号 ( ) @Nyxynyx 所以最后你的解决方案是创建一个大字符串? 是的,我为需要括号的问题部分创建了一个部分纯 SQL 查询字符串)并将其插入到$this-db-&gt;where()【参考方案2】:

我所做的是在 where 之后复制 and 子句,这实际上与长字符串选择相同。

$this->db->select()
  ->from('users')
  ->where('name !=', 'Joe')
  ->where('age <', 69)
  ->or_where('id <', $id)
  ->where('name !=', 'Joe');

一个大字符串的方式可能更好。

【讨论】:

在尝试按照@Jrod 的解决方案中描述的正确括号后,我采用了这种对我有用的方法!谢谢。【参考方案3】:

解决了。动态生成 SQL 查询并将其插入$this-&gt;db-&gt;where()。谢谢大家!

【讨论】:

呸,你丢失了字符串验证【参考方案4】:

默认情况下,CI 中没有 where 子句的分组。您必须扩展核心并添加能力。我通过以下方式做到了这一点:

class MY_DB_mysql_driver extends CI_DB_mysql_driver 
       
    public function __construct($params) 
    
    parent::__construct($params);
    
    /** 
     * This function will allow you to do complex group where clauses in to c and (a AND b) or ( d and e)
     * This function is needed as else the where clause will append an automatic AND in front of each where Thus if you wanted to do something
     * like a AND ((b AND c) OR (d AND e)) you won't be able to as the where would insert it as a AND (AND (b...)) which is incorrect. 
     * Usage: start_group_where(key,value)->where(key,value)->close_group_where() or complex queries like
     *        open_bracket()->start_group_where(key,value)->where(key,value)->close_group_where()
     *        ->start_group_where(key,value,'','OR')->close_group_where()->close_bracket() would produce AND ((a AND b) OR (d))
     * @param $key mixed the table columns prefix.columnname
     * @param $value mixed the value of the key
     * @param $escape string any escape as per CI
     * @param $type the TYPE of query. By default it is set to 'AND' 
     * @return db object.  
     */
    function start_group_where($key,$value=NULL,$escape,$type="AND")
    
        $this->open_bracket($type); 
        return parent::_where($key, $value,'',$escape); 
    

    /**
     * Strictly used to have a consistent close function as the start_group_where. This essentially callse the close_bracket() function. 
     */
    function close_group_where()
    
        return $this->close_bracket();  
    

    /**
     * Allows to place a simple ( in a query and prepend it with the $type if needed. 
     * @param $type string add a ( to a query and prepend it with type. Default is $type. 
     * @param $return db object. 
     */
    function open_bracket($type="AND")
    
        $this->ar_where[] = $type . " (";
        return $this;  
       

    /**
     * Allows to place a simple ) to a query. 
     */
    function close_bracket()
    
        $this->ar_where[] = ")"; 
        return $this;       
    

用法:

group_where_start(key,value)->where(key,value)->group_where_close() 

复杂的查询,如

open_bracket()->start_group_where(key,value)->where(key,value)->close_group_where()->start_group_where(key,value,'','OR')->close_group_where()->close_bracket() would produce AND ((a AND b) OR (d))

【讨论】:

优秀!!!我自定义我的驱动程序。你向 CI 推荐过吗?我可以把它放到 activeRec 中吗? 太棒了!它真的帮助了我!有人可能想阅读这篇文章以使其正常工作:github.com/bcit-ci/CodeIgniter/wiki/Extending-Database-Drivers 大家好,抱歉有一段时间了。不,我没有向 CI 建议过。只是出于对我的需要。随意将其放入 activeRec @NicolasThery。请将此设置为正确答案,以便我可以开始发布更多解决方案。干杯:)【参考方案5】:

在 Codeigniter 3.0.3 中,您可以这样做:

$this->db->select()
  ->from('users')
  ->where('name !=', 'Joe')
  ->group_start() // Open bracket
  ->where('age <', 69)
  ->or_where('id <', $id)
  ->group_end(); // Close bracket

或许有帮助

【讨论】:

【参考方案6】:

CI3 拥有你所需要的一切!

$this->db->select('*')->from('my_table')
        ->group_start()
                ->where('a', 'a')
                ->or_group_start()
                        ->where('b', 'b')
                        ->where('c', 'c')
                ->group_end()
        ->group_end()
        ->where('d', 'd')
->get();

https://www.codeigniter.com/userguide3/database/query_builder.html#query-grouping

【讨论】:

以上是关于在 Codeigniter 中对 WHERE 子句进行分组的主要内容,如果未能解决你的问题,请参考以下文章

CodeIgniter 或 Ignite Datatables 中的长尾 where 子句

在codeigniter中我如何使用where子句进行连接

Codeigniter Where 子句

Where 子句 CodeIgniter 中的 Active Record 问题

查询中的 WHERE 子句在 CodeIgniter 3 中无法正常工作

Codeigniter:MySQL Where 子句和引号