How can I do join with whereDoesntHave in Laravel - laravel

I'm trying to run a query in my Laravel 8.0 application. I've a problem doing join (circular) using the concept of whereDoesntHave() in Laravel. Since I'm using DB::table('...') and it has other conditions implemented, I'm having a brands table, projects table and project_associate_brand table, brand is in many-to-many relation with project, I want to find out the project counts in which brand and projects are not associated with each other, I'm trying to join the table twice one for getting projects associated with and other one to remove where it is not in relationship, so my query looks like:
$innerQuery = DB::table('brands as b')
->join('project_associate_brand as pabdoesnthave', 'b.id', '=', 'pabdoesnthave.brand_id')
->join('project_associate_brand as pab', function ($join) {
$join->on('b.id', '!=', 'pab.brand_id')
->where('pabdoesnthave.project_id', '!=', 'pab.project_id');
})
->join('projects as p', function ($join) {
$join->on('pab.project_id', '=', 'p.id')
->where('pabdoesnthave.project_id', '!=', 'p.id');
})
->select(DB::raw('b.id, b.title, COUNT(DISTINCT p.id) as projects_count'))
->whereNull('b.deleted_at')
->whereNull('p.deleted_at')
->groupByRaw('b.id');
return ProductBrandFilterResource::collection(DB::query()->fromSub($innerQuery, 't')
->select(DB::raw("
id,
`title`,
projects_count
"))
->orderBy('title', 'asc')
->groupBy('t.id')->get());
I'm unable get the desired results. To explain better I've table porject_associate_brand as:
brand_id project_id
1 1
1 2
1 3
2 1
2 3
If I want to get the list of brand where projects are not associated I get
id title project_count
1 ABC 3
2 PQR 3
For id 2 it is giving me 3 but actually it should be 1 as result.
Any better approach is appreciated. Thanks

Related

Laravel join 3 table and select raw sum

I have a 3 tables in Laravel project
First table "offers"
id
client
numer_offer
id_user
1
123
211/2022
11
2.
145
212/2022
23
Second table "clients"
id
name
adres
123
Mark
211/2022
145
Ben
212/2022.
A the last table "offer_items"
id
id_offer
product
amount
1
2
bags
14.56
2
2
bags2
16.50
And have a query:
$id_user = '11';
$offers = Offer::join('clients', 'clients.id', '=', 'offers.client')
->join('offer_items','.offer_items.id_offer', '=', 'offers.id')
->selectRaw(' sum(offer_items.amount) as suma, clients.name, offers.*')
->where('offers.id_user', $id_user)
->groupBy('offer_items.id_offer')
->Orderby('offers.id_offer')
->get();
the query works fine if I have a record in "offer_items", but if I have no record in the table, nothing shows, and I would like everything to be displayed and amount = 0.
any idea because yesterday I was up all day :(
use leftJoin instead of join at joining with offer_items, to retrieve data whether has records on offer_items or not , also i added IFNULL to treat null as 0
$id_user = '11';
$offers = Offer::join('clients', 'clients.id', '=', 'offers.client')
->leftJoin('offer_items','offer_items.id_offer', '=', 'offers.id')
->selectRaw(' sum(IFNULL(offer_items.amount,0)) as suma, clients.name, offers.*')
->where('offers.id_user', $id_user)
->groupBy('offers.id')
->Orderby('offers.id')
->get();
more details about different type of join , Mysql IFNULL

laravel group by fetch latest record from table

I have one table where I want to retrieve data group by the user but I want the latest entry in result how can I do that by using eloquent.
here is an eloquent query I am using.
Product::whereNotNull('user_id')
->orderBy('id','desc')
->groupBy('user_id')
->get();
here is my table
Id Name user_id
-------------------------
1 A 1
2 b 1
3 c 2
4 d 2
5 e 3
6 f 3
result my query is giving me
Id Name user_id
-------------------------
1 A 1
3 c 2
5 e 3
result i want
Id Name user_id
-------------------------
2 b 1
4 d 2
6 f 3
Product::whereRaw('id IN (select MAX(id) FROM products GROUP BY user_id)')
->whereNotNull('user_id')
->orderBy('id','desc')
->get();
You will need a nested query for that, i don't think you can avoid it but this solution should work.
GroupBy happens before OrderBy so you have to get your last record before you do your ordering
Try this :
$subquery = Product::orderBy('id','DESC');
$products = DB::table(DB::raw("({$subquery->toSql()}) as subquery"))
->whereNotNull('user_id')
->groupBy('user_id')
->get();
2nd way : use unique() method in collection (The unique method returns all of the unique models in the collection):
$products = Product::whereNotNull('user_id')
->orderBy('id','desc')
->get()
->unique('user_id');
Check out Laravel Docs
latest / oldest
The latest and oldest methods allow you to easily order results by date. By default, result will be ordered by the created_at column. Or, you may pass the column name that you wish to sort by:
$product = Product::latest()->first();

how to retrieve multiple table data with multiple criteria in laravel eloquent?

I want to retrieve data from 4 different table using laravel eloquent with multiple criteria.
an Overview of my table;
table 1
id
name
table 2
id
name
year
table1_id
table 3
id
name
description
table2_id
table 4
id
name
quarter
table3_id
below are their relations
table 1
hasMany -> table 2
table 2
belongsTo ->table1
HasMany->table2
table 3
belongsTo ->table2
HasMany->table3
table 4
belongsTo ->table3
I'd like to fetch the data by resource show with two parameters
and i tried this
$Report = Table1::whereHas('tabke1', function($query){
$query->where('year', 'like','%'.$year.'%');
})
->with('table2')->whereHas('table3', function($query){
$query->where('quarter', 'like', '%'.$quarters.'%');
})
->get();
but im receiving syntax error.
How can I retrieve the data from multiple table with multiple filter?
i tried this table query to understand more what i expect
SELECT `table1`.*, `table2`.*, `table3`.*, `table4`.*
FROM `table1`, `table2`, `table3`, `table4`
WHERE ((`table2`.* year = 2019) AND (`table4`.* quarter = 1))
I reckon there are two queries to achieve the results.
The first query is something like:
Table1::whereHas('table2', function ($query) {
$query->where('year', 2019);
})
->whereHas('table2.table3.table4', function ($query) {
$query->where('quarter', 1);
})
->get();
The second query is something like:
Table1::select('table1.*')
->join('table2', 'table1.id', '=', 'table2.table1_id')
->join('table3', 'table2.id', '=', 'table3.table2_id')
->join('table4', 'table3.id', '=', 'table4.table3_id')
->where('table2.year', 2019)
->where('table4.quarter', 1)
->distinct()
->get();
Regarding performance, I prefer the second query.

Laravel: Sorting a column in the Left Join

Lets say I have a simple table of users
id | userName
3 Michael
4 Mike
5 George
And another table of their cars and prices
id | belongsToUser | carPrice
1 4 5000
2 4 6000
3 4 8000
I would like to do a left join that would return the highest or lowest carPrice
At the moment, the query would return the last/first instance of that users carPrice.
I've tried entering the orderBy in various join queries but to no avail.
I have a helper function that would return the highest/lowest price on demand but I'm not sure how that would fit within this query as I would like to use laravels inbuilt paginate
This is the aggregate problem so here is the solvation:
DB::table('users')
->leftJoin('carPrices', 'belongsToUser', '=', 'users.id')
->select('users.*', DB::raw('MAX(carPrice) as highestCarPrice'), DB::raw('MIN(carPrice) as lowestCarPrice'))
->groupBy('users.id')
->get();

Laravel - Get an user who has specific relationships

I have a user with countries relationship. (hasMany)
user_id 1
country_id 1
user_id 1
country_id 2
...
What I want is to get those users who have both countries (country 1 and country 2) How can I do this? I'm reading http://laravel.com/docs/eloquent#querying-relations but I'm not very sure what to do.
edit: almost the solution
$users = \User::whereHas('countries', function($query) {
$countries_ids = [1, 2, 4];
$query->whereIn('users_countries.country_id', $countries);
})->get();
This will work as long as there are no duplicates in the pivot table (unique index for pair of fk keys for example):
$countries = [1,5,9];
User::whereHas('countries', function ($q) use ($countries) {
$q->whereIn('users_countries.country_id', $countries);
}, '=', count($countries) )->get();
In case there are duplicates, like:
user_id | country_id
1 | 1
1 | 2
1 | 1
Then you would need raw count(distinct ...) so you couldn't use whereHas, so I suggest this, which will be much faster:
$countries = [1,5,9];
User::join('users_countries as uc','uc.user_id', '=', 'users.id')
->whereIn('uc.country_id', $countries)
->having(DB::raw('count(distinct uc.country_id)'), '=', count($countries))
->groupBy('users.id')
->get(['users.*']);
You can do it the other way. Make the query on the country model. Add a function in the country model
public function user(){
return $this->belongsTo('user');//or if there is no user_id column in the countries table, use the ('model','local_key','foreign_key') pattern.
}
Then create an array with the country_ids, and que the country model.
$country_ids=array(4,67);
$countries=Country::where('id',$country_ids[0])->where('id',$country_ids[1])->get();
In order to get the users you should loop through like this
foreach($countries->user as $user)

Resources