Laravel query builder join where - php

I've got this query:
$query = QueryBuilder::for(Advertisement::class)
->with('locations');
The locations method on Advertisement looks like this:
public function locations()
{
return $this->belongsToMany(Location::class, 'advertisement_locations', 'advertisement_id', 'location_id');
}
So a advertisements belongsToMany locations in between is a pivot table called advertisement_locations.
Now I would only get the advertisements between a given long and latitude that's on the locations table.
How could I do this?

Use this:
$query = Advertisement::whereHas('locations', function($query) {
$query->whereBetween('long', [$min, $max])
->whereBetween('latitude', [$min, $max]);
});

Related

PHP/Laravel: SELECT and JOIN two tables

I have three tables as shown below and trying to join the expenses and allowance table on customers. I have tried using the code below but it returns null on expenses and allowances. I tried inner JOIN as well but didn't work.
I have tables as below:
customers(id, user_id, full_name)
expenses(id, customer_id, name, amount)
allowances(id, customer_id, name, quantity)
And i tried using the code below but doesn't work.
$logs = Customer::query()
->select([
"customers.id",
"customers.full_name",
"expenses.name as expenses_name",
"expenses.amount as expenses_amount",
"allowances.name as allowance_name",
"allowances.quantity as allowance_quantity"
])
->join('expenses', function (JoinClause $join) {
$join->type = 'left outer';
$join->on('expenses.customer_id', 'customers.id');
})
->join('allowances', function (JoinClause $join) {
$join->type = 'left outer';
$join->on('allowances.customer_id', 'customers.id');
});
return $logs->toJson();
I want output as:
{
id:'',
full_name:'',
expenses:{{expenses_name, expenses_amount},{expenses_name, expenses_amount}},
allowances:{{allowance_name, allowance_quantity},{allowance_name, allowance_quantity}}
}
Use the following Code:
$logs = Customer::select([
"customers.id",
"customers.full_name",
"expenses.name as expenses_name",
"expenses.amount as expenses_amount",
"allowances.name as allowance_name",
"allowances.quantity as allowance_quantity"
])
->leftjoin('expenses', 'customers.id','=','expenses.customer_id')
->leftjoin( 'allowances','customers.id','=','allowances.customer_id')
->get();
You can also use eloquent relationship.
define relations in Customer Model
public function expenses()
{
return $this->hasMany(Expense::class);
}
public function allowances()
{
return $this->hasMany(Allowance::class);
}
get Customers with relationship
$logs = Customer::with(['expenses','allowances'])->get();

Laravel Join query is not working for 4 tables

I have 4 tables
Table Name : Clinics
Fields: clinicID , clinicName
Table Name : locations
Fileds: locationID, clinicID,locationname
Table Name : Services
Fields: ServiceId , ServiceName
Table Name: LocationServices
Fields: locationServiceID, locationID , ServiceId
My requiremnt is that when i pass clinicID, i need to retrive Corresponding clinics service name, there may be more than one.
But when i tried join query is not working
Following is my code in controller
public function showClinic($id)
{
$clinic = Clinic::find($id);
$locations = Location::where('clinicID', $id)->get();
$locationsservices=\App\Clinic::with('locations');
var_dump($locationsservices);
die();
return view('clinic.show')->with(['locations' => $locations ,'clinic'=>$clinic]);
}
You can get this details by using relationships.
In the Clinic model,add
public function locations()
{
return $this->belongsTo('App\Models\Locations','clinicID','clinicID');
}
In the Locations model,add,
public function location_services()
{
return $this->hasOne('App\Models\LocationServices','locationID','locationID');
}
On the LocationServices model,
public function services()
{
return $this->hasOne('App\Models\Services','ServiceId','ServiceId');
}
You can get the result by,
$clinic_info = Clinic::find($id);
if(isset($clinic_info->locations))
{
if(isset($clinic_info->locations->location_services))
{
if(isset($clinic_info->locations->location_services->services))
{
echo $clinic_info->locations->location_services->services->ServiceName;
}
}
}
Reference Maybe HelpFull for You
Multi Joins
$data = DB::table('city')
->join('state', 'state.state_id', '=', 'city.state_id')
->join('country', 'country.country_id', '=', 'state.country_id')
->select('country.country_name', 'state.state_name', 'city.city_name')
->get();
return view('join_table', compact('data'));

Issue with group by laravel and sql

Firstly I have problem which count products which are sold every day. In sql I have query
select product_name, sum(quantity) as quantity from invoice_product
join invoices on invoices.id = invoice_product.invoice_id
join products on products.id = invoice_product.product_id
where invoices.issued_at = '2019-05-16'
and products.`made_by_us` = 1
group by product_name
It show me interesting for me information but I used product_name to make group by but I should use product_id - I need show name too but I don't know how to do it.
Secondly I want to use it in Laravel so maybe someone know which is it possible to do it in Eloquent?
Thank you in advance :)
I would go with withCount() combined with select(DB::raw()), like this:
$products = Product::withCount(['invoices as quantity' => function ($query) {
$query->select(DB::raw('sum(quantity)'));
}])->get();
Then, you can access each quantity sum like this:
$quantity = $products->first()->quantity;
You would need to update your model relationships to achieve that.
Models:
InvoiceProduct Model
class InvoiceProduct extends Model
{
protected $table = 'invoice_product';
protected $guarded = [
'id',
];
}
public function invoice()
{
return $this->belongsTo('App\Invoice'); // Assuming `Invoice` Model is directly in app folder
}
public function product()
{
return $this->belongsTo('App\Product'); // Assuming `Product` Model is directly in app folder
}
Controller:
$full_query = InvoiceProduct::whereHas('invoice', function ($query) {
return $query->where('issued_at', '2019-05-16');
})->whereHas('product', function ($query) {
return $query->where('made_by_us', 1);
});
$product_names = $full_query->get(['product_name']);
$total_quantities = $full_query->sum('quantity');

Laravel Builder Scope with Union and many-to-many relationship

I have a notifications table (and model)
notifications table columns are thus:
id
title
body
is_public
...
I also have a users table (and model)
users table columns:
id
username
...
I also have a pivot notification_user table
columns:
user_id
notification_id
many-to-many relationship is set on both Notification and User models thus:
Notification.php
public function users()
{
return $this->belongsToMany('App\Api\V1\Models\User');
}
User.php
public function notifications()
{
return $this->belongsToMany('App\Api\V1\Models\Notification');
}
Now inside Notification.php I want to set a scope. In the scope I need to get public notifications and the current user's
private notifications in a single SQL query. from my table structure, public notifications are where is_public == 1. Private notifications are associated on the pivot table.
to achieve this, inside my Notification.php, I also have this setup:
public function scopePublicAndPrivate(Builder $query)
{
return $this->public($query)->union($this->private($query));
}
public function scopePublic(Builder $query)
{
return $query->where('is_public', 1);
}
public function scopePrivate(Builder $query)
{
$user = JWTAuth::parseToken()->authenticate(); //using JWT to get a user.
return $user->notifications();
}
Now when I try Notification::publicAndPrivate()->get() inside a controller, I get:
Illuminate\Database\QueryException with message 'SQLSTATE[21000]: Cardinality violation: 1222 The used SELECT statements have a different number of columns (SQL: (select * from `notifications` where `is_public` = 1) union (select * from `notifications` inner join `notification_user` on `notifications`.`id` = `notification_user`.`notification_id` where `notification_user`.`user_id` = 1))
Please I'll appreciate any help with getting this to work or a better solution.
I believe you should change:
return $user->notifications();
to something else, for example:
return $query->where('user_id', $user->id);
or maybe
return $query->whereHas('users', function($q) use ($user) {
$q->where('id', $user->id);
});
This is because in one query you are not using any join and in second you do and you are getting different number of columns for union parts.

Laravel Eloquent: filtering model by relation table

I have places and locations tables.
Place could have many locations. Location belongs to Place.
Place:
id
title
Location:
id
place_id
floor
lat
lon
class Location extends Model {
public function place()
{
return $this->belongsTo('App\Place');
}
}
And
class Place extends Model {
public function locations()
{
return $this->hasMany('App\Location');
}
}
And i need to find places, that belongs only to 1st floor. select * from places inner join locations on places.id = locations.place_id where locations.floor = 1
How does it should be done in Eloquent?
Is something similar to
Place::where('locations.floor', '=', 1)->get() exists?
Yes, i know there is whereHas:
Place::whereHas('locations', function($q)
{
$q->where('floor', '=', 1);
})->get()
but it generates a bit complex query with counts:
select * from `places` where (select count(*) from `locations` where `locations`.`place_id` = `places`.`id` and `floor` = '1') >= 1
does not this works?
class Location extends Model {
public function place()
{
return $this->belongsTo('App\Place');
}
}
$locations = Location::where('floor', '=', 1);
$locations->load('place'); //lazy eager loading to reduce queries number
$locations->each(function($location){
$place = $location->place
//this will run for each found location
});
finally, any orm is not for database usage optimization, and it is not worth to expect nice sql's produced by it.
I haven't tried this, but you have eager loading and you can have a condition:
$places = Place::with(['locations' => function($query)
{
$query->where('floor', '=', 1);
}])->get();
Source
Try this :
Place::join('locations', 'places.id', '=', 'locations.place_id')
->where('locations.floor', 1)
->select('places.*')
->get();

Categories