How to aggregate query on related table's field in Laravel? - php

I have a One To Many (Inverse) relation on my laravel 5.4 application. There are two models Sale and Vehicle which are related and associated with the scene.
The relation on the Sale model is :
public function vehicle()
{
return $this->belongsTo('App\Models\Vehicle','vehicle_id');
}
Table sales has following fields :
id, vehicle_id, date_time, status etc.
Table vehicles has following fields :
id, reg_number, volume, status etc.
What I want is, sum of the field 'vehicles.volume' of Sale records within the search conditions.
I have tried some methods like the following one:
$query = Sale::where('status', 1);
$query = $query->where('date_time', '<', "2017-05-10 10:10:05");
$totalVolume = $query->whereHas('vehicle')->sum('vehicles.volume');
and it resulted in the following error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column
'vehicles.volume' in 'field list' (SQL: select
sum(vehicles.volume) as aggregate from sales where status = 1
and date_time < "2017-05-10 10:10:05" and exists (select * from vehicles where sales.vehicle_id =
vehicles.id))
hopefully waiting for a solution to 'get the sum of the volume of the sales' using eloquent query.
Edited

You need to use a join before summing the vehicles.volume column
$totalVolume = Sale::where('status', 1)
->where('date_time', '<', "2017-05-10 10:10:05")
->join('vehicles', 'vehicles.id', '=', 'sales.vehicle_id')
->select(DB::raw('sum(vehicles.volume) as total_volume');

select sum(volume) as aggregate from vehicles INNER JOIN sales ON vehicles.id=sales.vehicle_id

Related

Mysql,Php,Laravel checkbox error

I have the next question. How can I solve that problem? I have two tables vehicles and vehicles_extras. In the first table have a lot of columns. In the second table I have only 4 columns:
id, vehicle_id, vehicletype, vehicle_extra
The id is autoincrement, the vehicle_id is from the first table the id column, the 'vehicletype' is a string, type of the vehicle, the vehicle_extra is the number of the extras.
So I have a search form,where is the extras are checkboxes, extra[]. In a web.php I have this code:
$data1=DB::table('vehicles_extras')->where('vehicletype','$vt')->where('vehicle_extra',$extras);
....
if(Input::has('extras'))
$query->union($data1);
$data=$query->get();
for that I get error:
SQLSTATE[21000]: Cardinality violation: 1222 The used SELECT statements have a different number of columns (SQL: (select count(*) as aggregate from vm_vehicles where vehicletype = car) union (select * from vm_vehicles_extras where vehicletype = car and vehicle_extra = 2))
But ok, let's say it's working, but I have array with more values, so I want to use whereIn .
Any idea? I use Laravel 5.3.
First, you have to create one-to-many relation between vehicles and vehicles_extras.
Add the following relation in your Vehicle model:
public function vehicleExtras()
{
return $this->hasMany('App\VehicleExtra');
}
Then you can query it as:
Vehicle::whereHas('vehicleExtras', function ($q) use($extra) {
$q->where('vehicletype', 'car')
->whereIn('vehicle_extra', $extra);
})->get();

Join in Pivot tabel Laravel

I have following tables:
Food:
Foodid(pk)
FoodName
FoodImage
Description
Categories:
Category_id(pk)
CategoryName
Restaurant
Res_id(pk)
ResName
Address
category_food_restaurant
Category_id(fk)
Food_id(fk)
Res_id(fk)
Now I want to show Food items based on category name.For that I make query as:
$Category = DB::table('Food')
->select('Food.Food_id','Food.FoodName',
'Food.FoodImage','Categories.CategoryName')
->join('Categories','Categories.Category_id',
'=','category_food_restauarant.Category_id')
->where('Categories.CategoryName',
'=','Breakfast')->get();
But this gives me error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Food.Category_id' in 'on clause' (SQL: select Food.Food_id, Food.FoodName, Food.FoodImage, Categories.CategoryName from Food inner join Categories on Categories.Category_id = Food.Category_id where Categories.CategoryName = Breakfast).
Where is the problem.How I can show food items based on category by using these tables?
You are joining Food table and Categories table but there is no relation between them directly. So you have to join these two tables through category_food_restaurant. The following should work:
DB::table('category_food_restaurant')
->select('Food.Food_id','Food.FoodName',
'Food.FoodImage','Categories.CategoryName')
->join('Categories','Categories.Category_id',
'=','category_food_restaurant.Category_id')
->join('Food','Food.Food_id',
'=','category_food_restaurant.Food_id')
->where('Categories.CategoryName',
'=','Breakfast')->get();

QueryBuilder: Sum values of a pivot table

I'm new on Laravel & Eloquent. I have Users, Products and Votes tables on my DB. Users can vote (0 to 5) on products, so it is a "many to many" relationship, with the Votes table acting like a pivot:
Users: id, name, email, password
Products: id, name, model, brand
Votes: user_id, product_id, vote
I mapped this schema like this:
// User model:
public function product_votes()
{
return $this->belongsToMany('App\Product', 'votes')->withPivot('vote');
}
// Product model:
public function product_votes()
{
return $this->belongsToMany('App\User', 'votes')->withPivot('vote');
}
So John can vote 5 on product X and 0 on product Y. Bob can vote 2 on product X, 3 on product Y, and so on...
I'm trying to query all products, with the sum of votes of each one of them. Something like:
SELECT p.*, (SUM(v.vote) / COUNT(*)) as votes FROM products p INNER JOIN votes v on v.product_id = p.id GROUP BY p.id
How can I do that with QueryBuilder? My mapping is right?
The following will do the trick:
Product::select('products.*', DB::raw('SUM(vote)/COUNT(*) as votes'))
->join('votes', 'votes.product_id', '=', 'products.id')
->groupBy('products.id')
->get();
You can see the query that will be run by calling toSql() instead of get().

Codeigniter placeholder in select statement (select id, 0 as placeholder, ...)

I have query that counts ids in joined table. I need to do an union of returned table with another table in database.
The table returned from first query has 4 columns:
-group_id
-count
-name
-description
The table I want to unite with the first one has 3 columns:
-group_id
-name
-description
I run query through phpmyadmin and it worked perfectly. Query:
SELECT group_id, size, name, description
FROM(SELECT *, count(group_id) as size
FROM table1
GROUP BY group_id) as tmp
JOIN table2
ON tmp.group_id = table2.group_id
UNION
SELECT id, 0 as size, name, description
FROM table2
But when I try to make query with codeigniter, it won't work.
Error: Unknown column '0' in 'field list'
SELECT id, 0 as size, name, description
FROM table2
Here is the codeigniter code from module:
$this->db->select('group_id, size, name, description');
$this->db->from('(select *, count(group_id) as size from table1 group by group_id) as tmp');
$this->db->join('table2', 'tmp.group_id=table2.id');
$this->db->get();
$query1 = $this->db->last_query();
$this->db->select('id, 0 as size, name, description');
$this->db->from('table2');
$this->db->get();
$query2 = $this->db->last_query();
$this->db->query($query1. ' UNION ' .$query2);
$query = $this->db->get();
return $query->result_array();
To make the story short I need to know how to make placeholder with codeigniter or is there any other, better way to get the result I need?
You have to escape your select query by adding FALSE value as the second parameter of codeigniter's active record select() function.
So, it should be written like:
$this->db->select('id, 0 as size, name, description',FALSE);
When you add FALSE value to the second parameter of it, codeigniter won't keep the first parameter to be initialized by backtick character to the query.

Convert a Laravel Builder response to a Collection

I've got 3 tables - challenge, challenge_users, and climbs with the following definitions:
table challenge
id, name, start_date, end_date
table challenge_users
id, challenge_id, user_id
table climbs
id, user_id, date
I want to pull a list of climbs that fall within the dates of the challenge for any user in the challenge. The following SQL query does what I want:
select
*
from
climbs c
join
challenge_user cu on c.user_id=cu.user_id
where
date >= '2015-03-01'
and date <= '2015-03-06'
and cu.challenge_id=1;
I can build this with a query builder like
$climbs = DB::table('climbs')
->join('challenge_user', 'climbs.user_id', '=', 'challenge_user.user_id')
->where('climbs.date', '>=', $this->start_datetime->tz($tz)->startOfDay()->toDateString())
->where('climbs.date', '<', $this->end_datetime->tz($tz)->endOfDay()->toDateString())
->where('climbs.date', '<=', Carbon::now()->tz($tz)->endOfDay()->toDateString())
->get();
The problem is, this return an array of arrays. What I really want is to get a Collection of Climb models. I know I can do something like Climb::all()->filter(...), but then I'm doing a pretty large select (the SQL query ends up just being "select * from climbs").
Is there a way to use the DB to limit my results but still get my Collection of Climb models?
You can use Eloquent with a join, but you need to manually specify the select statement so that you're only getting the fields from the parent table and not the joined table:
$climbs = Climb::select('climbs.*')
->join('challenge_user', 'climbs.user_id', '=', 'challenge_user.user_id')
->where('climbs.date', '>=', $this->start_datetime->tz($tz)->startOfDay()->toDateString())
->where('climbs.date', '<', $this->end_datetime->tz($tz)->endOfDay()->toDateString())
->where('climbs.date', '<=', Carbon::now()->tz($tz)->endOfDay()->toDateString())
->get();

Categories