How to add brackets around WHERE conditions with Laravel query builder - mysql

I'm using the Laravel query builder to dynamically filter data based on a user's filter selections:
$query = DB::table('readings');
foreach ($selections as $selection) {
$query->orWhere('id', $selection);
}
$query->whereBetween('date', array($from, $to));
$query->groupBy('id');
When I examine the SQL, I get something like this:
select count(*) as `count` from `readings` where `id` = 1 or id` = 2 and `date` between "2013-09-01" and "2013-09-31" group by `id`;
But what I need is something like this (with brackets around the or statements):
select count(*) as `count` from `readings` where (`id` = 1 or id` = 2) and `date` between "2013-09-01" and "2013-09-31" group by `id`;
How do I add brackets around WHERE conditions with Laravel query builder?

Very useful, I use this:
->where(function ($query) use ($texto){
$query->where('UPPER(V_CODIGO)', 'LIKE', '%'.Str::upper($texto).'%')
->orWhere('UPPER(V_NOMBRE)', 'LIKE', '%'.Str::upper($texto).'%');
});

I couldn't find this in documentation, whereNested was what I was looking for. Hope it helps anybody.
$q->whereNested(function($q) use ($nameSearch) {
$q->where('name', 'LIKE', "%{$nameSearch}%");
$q->orWhere('surname', 'LIKE', "%{$nameSearch}%");
});
Note: This is on Laravel 4.2

Solved this myself by using a closure, as described in Parameter Grouping in the query builder documentation.
$query = DB::table('readings');
$this->builder->orWhere(function($query) use ($selections)
{
foreach ($selections as $selection) {
$query->orWhere('id', $selection);
}
});
$query->whereBetween('date', array($from, $to));
$query->groupBy('id');

Sometimes you may need to group several "where" clauses within parentheses in order to achieve your query's desired logical grouping. In fact, you should generally always group calls to the orWhere method in parentheses in order to avoid unexpected query behavior. To accomplish this, you may pass a closure to the where method:
$users = DB::table('users')
->where('name', '=', 'John')
->where(function ($query) {
$query->where('votes', '>', 100)
->orWhere('title', '=', 'Admin');
})
->get();
As you can see, passing a closure into the where method instructs the query builder to begin a constraint group. The closure will receive a query builder instance which you can use to set the constraints that should be contained within the parenthesis group. The example above will produce the following SQL:
select * from users where name = 'John' and (votes > 100 or title = 'Admin')

You can use WHERE IN here for the same effect:
$query = DB::table('readings');
$query->whereIn('id', $selection)
$query->whereBetween('date', array($from, $to));
$query->groupBy('id');

Related

How to write a where not in query in laravel?

I want to write a Where not in query in laravel. I wrote in sql it's working fine please help me convert the query to laravel.
This is the query...
SELECT *
FROM `apiaccessauth`
WHERE `site_name` NOT IN (
SELECT `site_name`
FROM `API_site_access_log`
WHERE `created_at` LIKE '%2021-10-15%'
);
If you want to use Eloquent, it'll be like below
Eloquent model
<?php
namespace App\Modules\Vehicle\Models;
use Illuminate\Database\Eloquent\Model;
class ApiAccessAuth extends Model
{
protected $table = 'apiaccessauth';
}
Your query
ApiAccessAuth::whereNotIn('site_name', function ($query) {
$query->from('API_site_access_log')
->select('site_name')
->whereDate('created_at', '2021-10-15');
})->get();
If you want to use query builder, it'll be like below
use Illuminate\Support\Facades\DB;
DB::table('apiaccessauth')
->whereNotIn('site_name', function ($query) {
$query->from('API_site_access_log')
->select('site_name')
->whereDate('created_at', '2021-10-15');
})->get();
Perhaps you would like to refactor your query to
SELECT a.*
FROM `apiaccessauth` a,
`API_site_access_log` b
WHERE
a.`site_name` = b.`site_name` AND
b.`site_name` NOT LIKE '%2021-10-15%'
so with query builder
$result = DB::table('apiaccessauth')
->join('API_site_access_log', 'API_site_access_log.site_name', '=', 'apiaccessauth.site_name')
->where('API_site_access_log.site_name', 'not like', "%2021-10-15%")
->get();
Pehaps you need a left or outer Join, depending what you want

how to run mysql query in Laravel

I want to transform my MySql query into a Query in Laravel but I really don't know how to do this. I don't know how to rename in FROM like in SQL
My query is the following one :
SELECT f2.* FROM formation f2 WHERE f2.theme_id IN
(SELECT f.theme_id FROM user_formation uf JOIN formation f ON uf.formation_id = f.id WHERE uf.user_id = 2)
AND f2.id NOT IN
(SELECT formation_id FROM user_formation WHERE user_id = 2);
I tried something like this but ...
$q = Formation::query()
->from('formation AS f2')
->whereIn('f2.theme_id', function($r)
{
$r->select('f.theme_id')->from('user_formation AS uf')
->join('formation', function($join)
{
$join->on('uf.formation_id', '=', 'f.id')
->where ('uf.user_id', '=', $id)
});
});
->whereNotIn('f2.id', function($s){
$s->select('formation.id')
->from('user_formation')
->where('user_id', '=', $id)
})->get();
thanks for help.
If you want to run this raw query you can run:
$res = DB::select('
SELECT f2.*
FROM formation f2
WHERE f2.theme_id IN
(SELECT f.theme_id FROM user_formation uf JOIN formation f ON uf.formation_id = f.id WHERE uf.user_id = 2)
AND f2.id NOT IN
(SELECT formation_id FROM user_formation WHERE user_id = 2)');
Or you can rewrite this query in laravel query builder Eloquent ORM:
Formations::query()
->whereIn('formations.theme_id', function($q){
$user_formations_table = (new UserFormation)->getTable();
$formation_table = (new Formation)->getTable();
$q->select('paper_type_id')
->from($user_formations_table)
->join($formation_table, "$user_formations_table.formation_id", '=', "$formation_table.id")
->where("$user_formations_table.user_id", 2);
})->whereNotIn('formations.id', function($q){
$user_formations_table = (new UserFormation)->getTable();
$q->select('formation_id')
->where("$user_formations_table.user_id", 2);
})
->get();
Note that I have used models Formations, UserFormation, Formation Because you have used 3 different tables, you should add this models and specify tables to run ORM query
I advice to run first RAW query if there is no another need to run it with Eloquent
Hope this helps you
First of all, you need to fix your code indentations so you don't confuse yourself. Second, you placed semicolon in the wrong places. Third, you need to pass $id inside function because of the variable scope.
$q = Formation::query()
->whereIn('f2.theme_id', function($r) use ($id) {
$r->select('f.theme_id')->from('user_formation AS uf')
->join('formation', function($join) use ($id) {
$join->on('uf.formation_id', '=', 'f.id')
->where('uf.user_id', '=', $id);
}
);
})
->whereNotIn('f2.id', function($s) use ($id) {
$s->select('formation.id')
->from('user_formation')
->where('user_id', '=', $id);
})->get();
Note : If you are using VSCode, I suggest to use PHP Intelephense as it will help with autocomplete, syntax check, etc.

Laravel's Database Query Builder

I am trying to write a MySQL select query using Laravel's Database Query Builder
I have this mysql query:
SELECT * FROM `tweets` WHERE `user_id` = 1 OR `user_id` in (SELECT `follows_id` from `follows` where `user_id` = 1)
I am trying to write it for Laravel
$users = DB::table('tweets')
->where('user_id', '=', 1)
how can this be done?
You can do something like this even though it looks ugly.
$tweets = DB::table('tweets')
->where('user_id', 1)
->orWhereIn('user_id', DB::table('follows')->select('follows_id')->where('user_id', 1)->pluck('follows_id'))
->get();
I would suggest a SQL rewrite as OR and IN(SELECT ...) tends to optimize badly.
The SQL result might be wrong as you didn't provide example data and expected result see Why should I provide a Minimal Reproducible Example for a very simple SQL query? for providing those.
SELECT
tweets.*
FROM
tweets
WHERE
tweets.user_id = 1
UNION ALL
SELECT
tweets.*
FROM
tweets
INNER JOIN
follows ON tweets.user_id = follows.follows_id
WHERE
follows.user_id = 1
I believe the following Laraval code should do that. But not sure as i didn't program in Laravel for some time now.
<?php
$first = DB::table('tweets')
->select('tweets.*')
->where('user_id', '=', 1);
$second = DB::table('tweets')
->select('tweets.*')
->join('follows', 'tweets.user_id', '=', 'follows.follows_id')
->where('follows.user_id ', '=', 1)
->union($first)
->get();
?>

Query Builder : orderBy not working after group by

I have a primary query which will run following way. And I had to check a condition and if the condition fulfilled it will add a statement with the existing query. But it doesn't work in right way means i couldn't get the orderby function run with the existing one? Why's that or how to solve this?
$query = DB::table('users')
->join('products','products.auth_id','users.id')
->Join('reviews','products.id','reviews.product_id')
->select('products.*','users.avatar',DB::raw('(sum(rating)/count(user_id)) as rating'))
->where('products.status','=','1')
->groupBy('products.id')
->latest();
if($request->get('dropdown')!='0' && $request->get('dropdown')=='desc')
{
$query->orderBy('products.regular_price', 'desc') ;
}
$products = $query->get();
Try this
if($request->get('dropdown')!='0' && $request->get('dropdown')=='desc')
{
$query = $query->orderBy('products.regular_price', 'desc') ;
}
Note : You have added latest() function in your query. This function added following in your query
ORDER BY created_at DESC
Default parameter of latest() is created_at

mysql join ON and AND to laravel eloquent

I've been able to get the query result I need using the following raw sql:
select `person`.`id`, `full_name`, count(actions.user_id) as total
from `persons`
left join `actions`
on `actions`.`person_id` = `persons`.`id`
and `actions`.`user_id` = $user
where `type` = 'mp'
group by `persons`.`id`
But I haven't been able to get it working in eloquent yet.
Based on some similar answers, I'd tried functions within ->where() or leftJoin(), but the count of each person's actions isn't yet being filtered by $user. As it stands:
$query = Person::leftJoin('actions', function($q) use ($user)
{
$q->on('actions.person_id', 'persons.id')
->where('actions.user_id', $user);
})
->groupBy('persons.id')
->where('type', 'foo')
//->where('actions.user_id', '=', $user)
->get(['persons.id', 'full_name', DB::raw('count(actions.id) as total')]);
I'm at least heading in roughly the right direction, right...?
If it's relevant, the Persons.php model has two actions relationships:
public function actions()
{
return $this->hasMany('Action');
}
public function actionsUser($id)
{
return $this->hasMany('Action')->where('user_id', $id);
}
So, for reference, I solved it like so:
$query = Person::leftJoin('actions', function($q) use ($user)
{
$q->on('actions.person_id', '=', 'persons.id')
->where('actions.user_id', '=', "$user");
})
->groupBy('persons.id')
->where('type', 'foo')
->get(['persons.id', 'full_name', DB::raw('count(actions.id) as total')]);
The ->where() clause within leftJoin, oddly, needs the speech marks for the variable to be passed through the sql query correctly (likewise, '2' doesn't seem to work while "2" does).
I found that the where doesn't always work on the leftJoin clause
If in the future you get any trouble with it, I'd suggest you using this:
$query = Person::leftJoin('actions', function($q) use ($user)
{
$q->on('actions.person_id', '=', 'persons.id')
->on('actions.user_id', '=', "$user");
})
->groupBy('persons.id')
->where('type', 'foo')
->get(['persons.id', 'full_name', DB::raw('count(actions.id) as total')]);
Hope it helps someone.
When laravel eloquent just start getting complex like this
For more flexibility and readability I'll just use plain sql statement then hydrate the results.
$sql = "
SELECT `person`.`id`,
`full_name`,
count(actions.user_id) AS total
FROM `persons`
LEFT JOIN `actions`
ON `actions`.`person_id` = `persons`.`id`
AND `actions`.`user_id` = $user
WHERE `type` = 'mp'
GROUP by `persons`.`id`
";
$query = Person::hydrate(
DB::select( $sql )
);