phpcodeigniterwhere-clausequery-builderlogical-grouping

How to compose a SELECT query with WHERE not equals AND at least one of multiple LIKE conditions in CodeIgniter


I find myself having a problem with this particular CodeIgniter MySQL query.

I'm trying to search my database rows where any of the 3 fields/columns contains the same phrase as the search string but the "status" must not be marked as "deleted".

I first tried:

$this->db->where('status !=', 'deleted');
$this->db->like('meta_title', $string);
$this->db->or_like('name', $string);
$this->db->or_like('text_full', $string);

But it just ignored the meta_title field completely, it wouldnt compare or look into "meta_title" at all. Then I tried the following based on someone else's stackexchange question and it fixed that problem, but now it ignores:

WHERE `status` != 'deleted'

My code

$rows = $this->db->query("SELECT * FROM `categories` WHERE `name` LIKE '%$string%' OR `meta_title` LIKE '%$string%' OR `slug` LIKE '%$string%' OR `text_full` LIKE '%$string%' AND `status` != 'deleted' ")->result_array();
    
var_dump($rows); 
echo $this->db->last_query(); die();

This returns all the rows, even the rows marked as deleted,

I also tried without the back ticks and I also tried

`status` NOT LIKE 'deleted'

Like this

$rows = $this->db->query("SELECT * FROM `categories` WHERE `name` LIKE '%$string%' OR `meta_title` LIKE '%$string%' OR `slug` LIKE '%$string%' OR `text_full` LIKE '%$string%' AND `status` NOT LIKE 'deleted' ")->result_array();

The result of

echo $this->db->last_query(); die();

is:

SELECT * FROM `categories` WHERE `name` LIKE '%buyer%' OR `meta_title` LIKE '%buyer%' OR `slug` LIKE '%buyer%' OR `text_full` LIKE '%buyer%' AND `status` != 'deleted' 

Ive also tried placing WHERE status != 'deleted' in the beginning of the query

I'm not very proficient in web dev, but I have played around a bit with this problem. Unfortunately, I've reached the point where I need help to understand what I'm doing wrong.


Solution

  • When you have the OR operator in a SQL predicate things get goofy. Essentially, your statement says,

    "I want rows that are not deleted - OR - rows that match my other conditions."

    You need to wrap the optional conditions in parenthesis to separate them from the conditions required on all rows:

    SELECT * 
    FROM `categories` 
    WHERE `status` != 'deleted'
    AND (`meta_title` LIKE '%$string%' 
          OR `slug` LIKE '%$string%' 
          OR `text_full` LIKE '%$string%'
          OR `name` LIKE '%$string%');