I don't see any difference in your query builders. You probably forgot to wrap the OR calls inside a single where.
Chaining orWhere clauses on a query doesn't produce correct SQL statements
Hi all
Today I had a quick script I needed to run to clear out some models from my DB I had some fields about the models but not their IDs, so I wrote quick query to pluck the uuid from. I had 3 bits of info to find the model by - orig, dest and dep_time_local (this is a Flight model) I simply did something like:
$flights = Flight::where([
'orig' => 'BEG',
'dest' => 'DOH',
['dep_time_local', 'like', '2022-12-18 11:45%']
)->orWhere([
'orig' => 'BOM',
'dest' => 'DOH',
['dep_time_local', 'like', '2022-12-19 04:15%']
])
// 9 more orWhere clauses.
->get()
All looks normal, right? No.
The SQL it generated returned 88 models, where I was only expecting 11.
I used this little script to check the data and SQL statement generated by Eloquent:
dd(vsprintf(str_replace('?', '%s', $flights->toSql()), collect($flights->getBindings())->map(function ($binding) {
return is_numeric($binding) ? $binding : "'{$binding}'";
})->toArray()));
What I found confused me. The first where clause behaved as expected, but the rest of them? Not so much
select *
from `flights`
where ((`orig` = 'BEG' and `dest` = 'DOH' and `dep_time_local` like '2022-12-18 11:45%') or
(`orig` = 'BOM' or `dest` = 'DOH' and `dep_time_local` like '2022-12-18 04:15%') or
(`orig` = 'BOM' or `dest` = 'DOH' and `dep_time_local` like '2022-12-19 04:15%') or
(`orig` = 'BOM' or `dest` = 'DOH' and `dep_time_local` like '2022-12-20 04:15%') or
(`orig` = 'BOM' or `dest` = 'DOH' and `dep_time_local` like '2022-12-21 04:15%') or
(`orig` = 'SEA' or `dest` = 'DOH' and `dep_time_local` like '2022-12-17 17:40%') or
(`orig` = 'SEA' or `dest` = 'DOH' and `dep_time_local` like '2022-12-18 17:40%') or
(`orig` = 'LAX' or `dest` = 'DOH' and `dep_time_local` like '2022-12-18 15:05%') or
(`orig` = 'LAX' or `dest` = 'DOH' and `dep_time_local` like '2022-12-19 15:05%') or
(`orig` = 'LAX' or `dest` = 'DOH' and `dep_time_local` like '2022-12-20 15:05%') or
(`orig` = 'LAX' or `dest` = 'DOH' and `dep_time_local` like '2022-12-21 15:05%') and `deleted_at` is null)
and `flights`.`deleted_at` is null
You'll notice that the first condition goes and, and, like But every one following goes or, and, like
This can't be the correct behaviour, surely? When I changed the builder query to:
$flights = Flight::where([
'orig' => 'BEG',
'dest' => 'DOH',
['dep_time_local', 'like', '2022-12-18 11:45%']
)->orWhere([
['orig', 'BOM'],
['dest', 'DOH'],
['dep_time_local', 'like', '2022-12-19 04:15%']
])
// 9 more orWhere clauses.
->get()
I got the expected SQL statement (where each condition set follows and, and, like) and the correct result set of 11 records
Has anyone else come across similar behaviour?
Edit: I am running on PHP 7.4 on a Fedora Linux install, using Laravel 8.x latest
Edit 2:
Using arrow syntax inside the orWhere clause is what told it to generate the or condition inside the SQL statement. Using square brackets, as per comments and my other snippet, instead denotes an and condition
At least, this is how I've understood the problem
Please or to participate in this conversation.