codeigniter like clause overriding where clause - sql

At least that is what seems to be happening. I'm trying to create a search bar for a website and it does work, except it's not reading a where clause which would only pull back approved content. You can kind of see why that would be an issue.
Anyway, this is what I have in my model
$match = $this->input->post('search');
$this->db->where('approved', 'y');
$this->db->like('description', $match);
$this->db->or_like('title', $match);
$this->db->or_like('body', $match);
$this->db->or_like('author', $match);
$query = $this->db->get('story_tbl');
return $query->result();
and when I print out the query, it seems like it's seeing the where clause, but when I get the stuff back it's pulling things that are not approved or under review.
Here is my printed query
SELECT * FROM (`story_tbl`) WHERE `approved` = 'y' AND `description` LIKE
'%another%' OR `title` LIKE '%another%' OR `body` LIKE '%another%' OR
`author` LIKE '%another%'

Your query should be
SELECT * FROM (`story_tbl`) WHERE `approved` = 'y' AND (`description` LIKE
'%another%' OR `title` LIKE '%another%' OR `body` LIKE '%another%' OR
`author` LIKE '%another%')
Check those brackets. So, your best option is to use plain $this->db->query(). If you insist on using active records, you have to do it like this for those brackets -
$match = $this->input->post('search');
$this->db->where('approved', 'y');
$this->db->where("(`description` LIKE '%$match%'");
$this->db->or_where("`title` LIKE '%$match%'");
$this->db->or_where("`body` LIKE '%$match%'");
$this->db->or_where("`author` LIKE '%$match%')");
$query = $this->db->get('story_tbl');
EDIT:
true AND true OR true OR true //true
false AND true OR true OR true //true just like your where clause is ignored
false AND false OR false OR true //Still true
false AND true OR false OR false //false
false AND false OR false OR false //false
So this query will return all the rows where approved = 'y' OR where title, body, author matches 'another'
In my posted query
true AND (true OR true OR true) //true
false AND (true OR true OR true) //false, where clause is checked
true AND (false OR false OR false) //false
true AND (true OR false OR false) //true
Which will return the rows where approved = 'y' AND also either title or body or author or description matches 'another'. I believe this is what you want to achieve.

You can use codeigniters's group_start() and group_end() for this. The code can be modified like this
$match = $this->input->post('search');
$this->db->where('approved', 'y');
$this->db->group_start(); //start group
$this->db->like('description', $match);
$this->db->or_like('title', $match);
$this->db->or_like('body', $match);
$this->db->or_like('author', $match);
$this->db->group_end(); //close group
$query = $this->db->get('story_tbl');
return $query->result();

Related

sql query last_messages displays wrong message

i have query like this, but displays wrong last_message.
$users = Message::join('users', function ($join) {
$join->on('messages.from_id', '=', 'users.id')
->orOn('messages.to_id', '=', 'users.id');
})
->where(function ($q) {
$q->where('messages.from_id', auth()->user()->id)
->orWhere('messages.to_id', auth()->user()->id);
})
->where('users.id','!=',auth()->user()->id)
->select([
'users.id',
'users.name',
'users.avatar',
DB::raw('MAX(messages.created_at) max_created_at'),
DB::raw('MAX(messages.body) last_message'),
DB::raw('CASE WHEN(COUNT(messages.is_read) FILTER (WHERE is_read = false
AND messages.from_id != '.auth()->user()->id.') = 0) THEN true ELSE false END is_read'),
DB::raw('COUNT(messages.is_read) FILTER (WHERE is_read = false
AND messages.from_id != '.auth()->user()->id.') count_unread')
])
->orderBy('max_created_at', 'desc')
->groupBy('users.id')
->paginate($request->per_page ?? 20)
->withQueryString();
when i change
DB::raw('MAX(messages.body) last_message'),
to
DB::raw('messages.body ORDER BY messages.created_at DESC LIMIT 1 last_message'),
display error messages like this, syntax error at or near "last_message". How to fix this?
You want to alias the column, not the statement. Try to change it to:
messages.body last_message ORDER BY messages.created_at DESC LIMIT 1
So you need first order the records based on some column and then return the first record of that list.
$cart_data = ScCart::orderBy('created_at', 'asc')->first();
$cart_data = ScCart::orderBy('created_at', 'desc')->first();
This will work for first and last record created in that table.

hx-trigger only when boolean is true

I have 2 triggers here. I want to disable the second trigger (id_indoor_manufacturer) if manufacturer_boolean is false. I've tried adding a filter to the trigger, but it doesn't work (see below)
manufacturer_boolean = forms.BooleanField(
initial=True,
widget=forms.CheckboxInput(attrs={
'class':'form-control',
'autocomplete': 'off',
'hx-get': '/companies/outdoor_manufacturer/',
'hx-target': '#id_outdoor_manufacturer',
'hx-include': '#id_indoor_manufacturer, #id_outdoor_manufacturer',
'hx-trigger': 'change from:#id_manufacturer_boolean, change[target == true] from:#id_indoor_manufacturer',
}))

Laravel/SQL: where column Equals NOT and NULL

LARAVEL 5.4 (but probably it's a more general SQL question)
Hello! I have a table with a structure:
Suppose it's my model 'Table'.
I want a query which:
uses (receives) variables :
$id of array ['id', 'string', integer]
where string is '<' or '>'
$status_not_bad = bool;
(if true - include all rows where 'status' !== 'bad' AND 'status' IS NULL);
for example, we are given:
$id = [['id', '>', 0]];
$status_not_bad = true;
Table::thisquery() ... ->get();
"get rows where status is not bad and id > 0" returns rows 1 and 3.
but if we given:
$id = [['id', '<', 3]];
$status_not_bad = true;
Table::thisquery() ... ->get();
"get rows where status is not bad and id < 3" returns row 1
(it should be same query which return those results using those variables).
Probably you end with something like this:
if ($status_not_bad) {
$nStatus = 'bad';
} else {
$nStatus = 'good';
}
Table::thisquery()->where('status', '<>', $nStatus)
->whereNotNull('status')
->where($id[0], $id[1], $id[2])
->get();
But it would be a good idea to check $id keys first.
Since row id = 3 you need <= in your where statement to have that row included in the result set
$id = ['id', '<=', 3];
So, I this works:
$chain = Sample::when($status_not_bad, function($query){
return $query->where('status', '<>', 'bad')
->orwhereNull('status');
})
->where([$id])
->get();

sql query in Rails where value IS BLANK (0 or nil)

In Rails there is the method item.property.blank? which is true for property being "0" or nil or whitespace.
How can I make an sql query to check if a value is blank?
I now have:
Item.where("name = 'Testname' AND property <> '1'")
which shows me all items with name = 'Testname' and property = '0', but not those with property = nil (not defined).
How should my sql query be to be equivalent to
Item.where("name = 'Testname' AND property IS BLANK")
so that all items with property = '0' and property = nil are included to the search results?
Item.where("property IN ('0','') OR property IS NULL")
or more exactly...
Item.where("name = 'Testname' AND (property IN ('0','') OR property IS NULL)")
Without using SQL strings, you can do this:
Item.where(name: 'Testname', property: [nil, '0', ''])
It will produce the SQL query
SELECT `items`.* FROM `items`
WHERE `items`.`name` = 'Testname'
AND (`items`.`property` IN ('0', '') OR `items`.`property` IS NULL)

Searching with CDbCriteria

Is there any way to make a CDbCriteria search (as in compare()) in the fields I'm selecting, but using the model's search() method instead of having to manually add the compare() conditions?
Note that I'm aiming at a solution that will let me write some fewer lines, nothing more and nothing less. So, if the solution is something really hacky and/or mesy, I'll just go for the "add-a-few-compares()" method.
My current code:
$criteria = new CDbCriteria;
$criteria->with = array('A', 'B', 'C', 'D', 'E');
$criteria->compare("A.field1", "test", false, 'OR');
$criteria->compare("A.field2", "test", false, 'OR');
$criteria->compare("B.field1", "test", false, 'OR');
$criteria->compare("B.field2", "test", false, 'OR');
$dataProvider = new CActiveDataProvider('Z', array(
'criteria'=>$criteria,
//pagination...
//more options...
));
Update: It seems that you are actually looking(from comments below this answer) for partial matches, and for that you will have to pass true to your compare calls:
$criteria->compare("A.field1", "test", true, 'OR');
Even that can be passed to addCondition:
$criteria->addCondition('A.field1 LIKE "%test"','OR');
// or with params as below
$criteria->addCondition('A.field2 LIKE :test','OR');
$criteria->params=array(
':test'=>'%test%',
);
As i have already mentioned in the comments, i don't think it'll be possible to use each model's default search() method. There are other alternatives though, for instance you can use addCondition instead:
$criteria = new CDbCriteria;
$criteria->with = array('A', 'B', 'C', 'D', 'E');
$criteria->together = true; // you'll need together so that the other tables are joined in the same query
$criteria->addCondition('A.field1 = "test"','OR');
$criteria->addCondition('A.field2 = "test"','OR');
// and so on
I would suggest going with the above, because compare (doc-link) should actually be used in cases when you want to "intelligently" determine the operator for comparision, for example: if you are taking the test values from user input and the user is allowed to use operators (<,>,<= etc). After determining the operator to be used in the condition, compare calls other functions accordingly, including addCondition. So using addCondition will atleast avoid those unnecessary checks.
Further if all you have to do is check equality only, i.e if your sql's WHERE is supposed to be:
WHERE A.field1 = "test" OR A.field2 = "test"
then you don't even need addCondition, and you can simply use a more complex condition (doc) :
$criteria->condition='A.field1 = "test" OR A.field2 = "test"';
// or even better if you use params
$criteria->condition='A.field1 =:test1 OR A.field2 =:test2 OR B.field1 =:test3 OR B.field2 =:test3';
$criteria->params=array(
':test1'=>'test',
':test2'=>'anothertest',
'test3'=>'tests' // omitting ':' here for params also works
);