开发者

Codeigniter parentheses in dynamic Active Record query

I'm producing a query like the following using ActiveRecord

SELECT * FROM (`foods`) WHERE `type` = 'fruits' AND 
       `tags` LIKE '%green%' OR `tags` LIKE '%blue%' OR `tags` LIKE '%red%'

The number of tags and values is unknown. Arrays are created dynamically. Below I added a possible array.

$tags = array (                 
        '0'     => 'green'.
        '1'     => 'blue',
        '2'     => 'red'
);  

Having an array of tags, I use the following loop to create the query I posted on top.

$this->db->where('type', $type); //var type is retrieved from input value

foreach($tags as $tag):         
     $this->db->or_like('tags', $tag);
endforeach; 

The issue: I need to add parentheses around the LIKE clauses like below:

SELECT * FROM (`foods`) WHERE `type` = 'fruits' AND 
      (`tags` LIKE '%green%' OR `tags` LIKE '%blue%' OR `tags` LIKE '%red%')

I know how to accomplish this if the content within the parentheses was static but the foreac开发者_StackOverflow社区h loop throws me off..


From the CI wiki:

The codeignighter ActiveRecord feature allows you to create SQL queries relatively simply and database-independant, however there isno specific support for including parenthesis in an SQL query.

For example when you want a where statement to come out simmilarly to the folowing:

WHERE (field1 = value || field2 = value) AND (field3 = value2 || field4 = value2) 

This can be worked around by feeding a string to the CI->db->where() function, in this case you will want to specifically escape your values.

See the following example:

$value=$this->db->escape($value);
$value2=$this->db->escape($value2);
$this->db->from('sometable');
$this->db->where("($field = $value || $field2 = $value)");
$this->db->where("($field3 = $value2 || $field4 = $value2)");
$this->db->get(); 

A simmilar workaround can be used for LIKE clauses:

$this->db->where("($field LIKE '%$value%' || $field2 LIKE '%$value%')");
$this->db->where("($field3 LIKE '%$value2%' || $field4 LIKE '%$value2%')"); 


In the CI 3.0-dev you can add groups in query:

$this->db->select('id, title')
->group_start()
->or_like([ 'title' => $s, 'id' => $s ])
->group_end()                
->where([ 'b_del' => 0 ]);

Produces:

SELECT `id`, `title`, `venda1`
FROM `itens`
WHERE   
(
`title` LIKE '%a%' ESCAPE '!'
OR  `id` LIKE '%a%' ESCAPE '!'
 )
AND `b_del` =0 


One of best feature to save your query when you applying multiple where or_where clauses.

$this->db->group_start();
$this->db->where();
$this->db->or_where();
$this->db->group_end();

Happy Coding. :)


Going off of The Silencer's solution, I wrote a tiny function to help build like conditions

function make_like_conditions (array $fields, $query) {
    $likes = array();
    foreach ($fields as $field) {
        $likes[] = "$field LIKE '%$query%'";
    }
    return '('.implode(' || ', $likes).')';
}

You'd use it like this:

$search_fields = array(
    'field_1',
    'field_2',
    'field_3',
);
$query = "banana"
$like_conditions = make_like_conditions($search_fields, $query);
$this->db->from('sometable')
    ->where('field_0', 'foo')
    ->where($like_conditions)
    ->get()


Just adding my successful solution:

$this->db->where("(table.field = $variable OR table.field IS NULL)");


use codeigniter 3

$this->db->select('*');
    $this->db->from($this->MasterMember);
    $this->db->group_start();
    $this->db->where($this->IDCardStatus, '1');
    $this->db->or_where($this->IDCardStatus, '2');
    $this->db->group_end();

    if ($searchKey1 != null) {
        $this->db->group_start();
        $this->db->like($this->MemberID, $searchKey1);
        $this->db->or_like($this->FirstName, $searchKey2);
        $this->db->or_like($this->LastName, $searchKey3);
        $this->db->group_end();
    }

    $this->db->limit($limit, $offset);


    $data = $this->db->get();

this is my native query

SELECT
    * 
FROM
    `Member` 
WHERE ( `Member`.`IDCardStatus` = '1' OR `Member`.`IDCardStatus` = '2' ) 
AND ( `Member`.`MemberID` LIKE '%some_key%' ESCAPE '!' OR `Member`.`FirstName` LIKE '%some_key%' ESCAPE '!' OR `Member`.`LastName` LIKE '%some_key%' ESCAPE '!' ) 
    LIMIT 10


Update for codeigniter 4:

$builder->select('*')->from('my_table')
        ->groupStart()
            ->where('a', 'a')
            ->orGroupStart()
                    ->where('b', 'b')
                    ->where('c', 'c')
            ->groupEnd()
    ->groupEnd()
    ->where('d', 'd')
->get();

// Generates:
// SELECT * FROM (`my_table`) WHERE ( `a` = 'a' OR ( `b` = 'b' AND `c` = 'c' ) ) AND `d` = 'd'

from official docs on: https://codeigniter.com/user_guide/database/query_builder.html#query-grouping


$likes = array (                 
    '0'     => 'green'.
    '1'     => 'blue',
    '2'     => 'red'
);  
$where_like = "("; 
$or_counter = 1;
foreach($likes as $like_key => $like_val):
    $or_content = ($or_counter > 1) ?'OR': '';
    $newlikeval = $this->db->escape_like_str($like_val);
    $where_like .= $or_content." `$like_key` LIKE  '%$newlikeval%' ";
    $or_counter++;
endforeach;
$where_like .= ")";
$this->db->where($where_like);


You can't add parentheses in ActiveRecord, but maybe WHERE IN is what you're looking for?

$names = array('Frank', 'Todd', 'James');
$this->db->where_in('username', $names);
// Produces: WHERE username IN ('Frank', 'Todd', 'James')
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜