laravel join with average of a column in another table - mysql

I have a Food model and Review model. in my reviews table in database I have two columns : food_id and rate. Each user can rate foods and rate is an integer number between 1~5.
I need to get all records in foods table and average of rate column in reviews where food_id is the id of each food.
$foods = Food::join('reviews', 'foods.id', '=', 'reviews.food_id')->select(
'foods.*',
'AVERAGE(reviews.rate) WHERE reviews.food_id = foods.id AS food_rate'
)->get();
And of course this code will raise SQLSTATE[42000]: Syntax error
How can I join with average of a column in another table?
SELECT foods.*, AVG(reviews.rate) AS food_rate
FROM foods
LEFT OUTER JOIN reviews
ON reviews.food_id = foods.id
GROUP BY foods.id
in fact this MYSQL code needs to be written with Laravel

$foods = Food::select(
'*',
\DB::raw('AVG(reviews.rate) AS food_rate'),
)->leftJoin('reviews', 'foods.id', '=', 'reviews.food_id')->groupBy('foods.id');
and we need to set 'strict' => false in config/database.php

Related

Laravel Eloquent query for left join

I have two tables available. 1) Users 2) Friendships. Following is the table structure:
Users Table have following columns
id
email
dob
password
first_name
last_name
username
gender
phone
country
Friendships table have following columns
id
sender_id
recipent_id
status
created_at
updated_at
Now I want to retrieve data from the "users" table using the "sender_id," which is the same as the "id" in the "users" table.
I'm using the left join to perform the required query as follow:
public function show_friend_request(){
$user_id = auth()->user()->id;
**//Below query will get the userID's of people who have sent the request to current user.**
$get_friend_requests = DB::table('friendships')->where('recipient_id',$user_id)
->where('status','pending')->get(['sender_id'])->first()->sender_id;
$show_friend_request_Data = DB::table('users')
->leftJoin('friendships', 'sender_id', '=', $get_friend_requests)
->get();
return $show_friend_request_Data ;
}
But when i executed the above code i'm getting the following error:
Illuminate \ Database \ QueryException
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'users.sender_id' in 'on clause'
select * from `users` left join `friendships` on `users`.`sender_id` = `63b8760f-826b-4c1c-aea9-23f1dff148db`
All you have to do is:
$show_friend_request_Data = DB::table('users')
->leftJoin('friendships', 'friendships.sender_id', '=', 'users.id')
->where('users.id', '=', $get_friend_requests)
->get();
I also suggest you to think of how to optimise the whole query to only 1 request and also how to get multiple friend requests at the time. Because now you're only getting the first friend pending friend request ;)

How to join tow times the same table?

I need to join twice the same table how do a do it in Codeigniter?
TABLE MATCH
match_id
team_home_id
team_away_id
score_home
score_away
group_id
round_id
winner
start_date
start_time
TABLE TEAM
team_id
name
code
This are the two tables I have to join. The table team has to join twice with a table match.
$this->db->select('*')
->from('match, team')
->join('team AS team_a', 'match.team_home_id = team_a.team_id')
->join('team AS team_b', 'match.team_away_id = team_b.team_id')
->get()->result();
My result is the match and just one of the teams :/
Thank you, Strawberry for your help.
On my query, I was getting always the last team joined because it looks like Codeigniter overwrites the columns with the same name, team_a.name and team_a.code are represented in the final result_array() as array key "name" and "code" the same as team_b.name and team_b.code.
So more than an alias for the tables I needed to add an alias for the columns:
$this->db->select('tips.stake, tips.odd,
matches.score_home, matches.score_away, matches.winner, matches.start_date, matches.start_time,
team_home.name AS team_home_name, team_home.code AS team_home_code, team_away.name AS team_away_name, team_away.code AS team_away_code');
$this->db->from('tips');
$this->db->join('matches', 'matches.match_id = tips.match_id');
$this->db->join('`teams` `team_home`', 'team_home.team_id = matches.team_home_id');
$this->db->join('`teams` `team_away`', 'team_away.team_id = matches.team_away_id');
$query = $this->db->get();

How to reduce loading time of sql query?

I had created a query to get a list of staffs using this query. It is run after checked the permission level of the login user.
if (Auth::user()->hasPermissionTo('All Sections')) {
$itemregistrations = DB::table('itemregistrations')
->join('sections', 'itemregistrations.sectionid', '=', 'sections.sectionid')
->join('categories', 'itemregistrations.categoryid', '=', 'categories.categoryid')
->join('operasi', 'itemregistrations.operasiid', '=', 'operasi.operasiid')
->select('itemregistrations.ItemRegistrationID','itemregistrations.name', 'itemregistrations.Nobadan', 'sections.sectionname', 'categories.categoryname', 'operasi.operasiname')
->get();
}
However, the query gets loading quite long, about a minute to finish loading. The list displayed about 1115.
How to reduce the loading time?
I read about eager loading to decrease the loading time. But my trial not success.
section is the department of staffs.
categories is the staff level
operasi is the grade of staff, related to categories, each category has its own operasiname.
This is the indexing on itemregistrations table.
I had installed laravel debugger and produce this result:
-6 views
-4 queries
select * from `users` where `id` = 1 limit 1
select `permissions`.*, `model_has_permissions`.`model_id` as `pivot_model_id`, `model_has_permissions`.`permission_id` as
`pivot_permission_id` from `permissions`
inner join `model_has_permissions` on `permissions`.`id` = `model_has_permissions`.`permission_id`
where `model_has_permissions`.`model_id` = 1 and `model_has_permissions`.`model_type` = 'App\User'
select `roles`.*, `model_has_roles`.`model_id` as `pivot_model_id`, `model_has_roles`.`role_id` as `pivot_role_id` from `roles`
inner join `model_has_roles` on `roles`.`id` = `model_has_roles`.`role_id`
where `model_has_roles`.`model_id` = 1 and `model_has_roles`.`model_type` = 'App\User'
select `itemregistrations`.`ItemRegistrationID`, `itemregistrations`.`name`,
`itemregistrations`.`Nobadan`, `sections`.`sectionname`, `categories`.`categoryname`, `operasi`.`operasiname`
from `itemregistrations` inner join `sections` on `itemregistrations`.`sectionid` = `sections`.`sectionid`
inner join `categories` on `itemregistrations`.`categoryid` = `categories`.`categoryid`
inner join `operasi` on `itemregistrations`.`operasiid` = `operasi`.`operasiid`
-1116 gates
The above query is filtered according to few permissions.
these are indexes for table involved:
role table index
permission table index
model has role table
role has permission table
for the DB side be sure you have proper index on the columns involved in JOIN
sections sectionid
categories categoryid
operasi operasiid
expecially a composite index on
itemregistrations (sectionid , categoryid , operasiid )
anyway the load of 1256 si pretty unuseful in real app ..
for this you could reduce the loading time for the data show using pagination
based on you cardinality you should build an index
itemregistrations (operasiid, sectionid , categoryid )
could be you need remove the index on the same columns involved and leave only the composite ...

Join 4 tables with common field in Codeigniter

I have four tables named tblproducts, tblprospecification, tblcomspecification and tblledtvpecification.
The fields of tblproducts are proid, product_code, product_name,
pro_img, pro_resize_img, pro_thumb_img and it stores products
details.
The second table is tblprospecification stores the mobile specifications and it has column speid, proid, in_the_box ,model_number, model_name, color, browse_type, sim_type.
The third table is tblcomspecification for storing computer specification and its column are comspecificid,proid, modelname, color, series etc. and the fourth column istblledtvpecification for storing ledtv specification and its column are tvspecificid, modelname, dsize, stype_id, hd_techno.
I am using the query below enter
$query= $this->db->select( 'tblproducts.proid as pro_id, product_code, product_name, pro_img, pro_resize_img, pro_thumb_img, tblprospecification.proid as product_id , in_the_box ,model_number, model_name, tblprospecification.color as mobile_color, browse_type, sim_type ,tblcomspecification.proid as product_id, tblcomspecification.modelname as com_moledname, series, tblcomspecification.color as com_color, tblledtvpecification.proid, tblledtvpecification.modelname as ledtv_modelname, dsize,stype_id, hd_techno')
->from('tblproducts')
->join('tblprospecification','tblproducts.proid = tblprospecification.proid ' ,'left')
->join('tblcomspecification','tblproducts.proid = tblcomspecification.proid', 'left')
->join('tblledtvpecification','tblproducts.proid = tblledtvpecification.proid' ,'left')
->where('tblproducts.proid',$proid)
->get();
return $query->result();
When I execute the query, it will return the data after join from tblproducts and tblprospecification only. It returns blank data for tblledtvpecification, tblcomspecification.

Mysql total amount (price) in cart from many tables

I met what I believe is a very common problem with mysql and e-commerce shop ... though I can't find answer for this.
I've got shop which has not one product table but many ... for example in one shop has vinyls, studio gear etc ... so we've got many tables with different product details ... the thing is I need to get total amount (price) of products in cart from many tables
public static function GetTotalAmount() {
$params = array(
':cart_id' => self::GetCartId()
);
$sql = 'SELECT SUM(v.price) AS total_amount '.
'FROM shopping_cart sc '.
'INNER JOIN vinyl v '.
'ON sc.product_id = v.id AND sc.department_id = 1 '.
'WHERE sc.cart_id = :cart_id AND sc.buy_now;';
$v = DataBase::FetchOne($sql, $params);
$sql = 'SELECT SUM(sg.price) AS total_amount '.
'FROM shopping_cart sc '.
'INNER JOIN studio_gear sg '.
'ON sc.product_id = sg.id AND sc.department_id = 2 '.
'WHERE sc.cart_id = :cart_id AND sc.buy_now;';
$sg = DataBase::FetchOne($sql, $params);
return $sg + $v;
}
As you might see I made this with ugly way .. maybe you can help me show how to get SUM() of possible N tables counted from N.price.
You can use UNION ALL
SELECT SUM(price) FROM ((SELECT SUM(price) as price FROM table1 WHERE ...) UNION ALL (SELECT SUM(price) as price FROM table2 WHERE ...) UNION ALL ....)
A quick tip (if you can) - merge all the products tables into one table and operate on that (you'll also have to implement categories and custom attributes for products though). Otherwise you will have a mess when you add new shops.
You can create a (materialized) view with just the necessary columns of the product tables, - product_id and price
Once you have the view (vw_products) you can just do an inner join of shopping cart table with the view and then get the sum.
SELECT sum(vw.price) FROM
shopping_cart sc INNER JOIN vw_products vw
ON sc.product_id = vw.id and sc.department_id IN (1,2,...)
WHERE sc.cart_id = :cart_id AND sc.buy_now;
If you have many rows and if the prices don't change often (every few minutes)
I would suggest creating a table and populating it with the result of above query.
Every day or after every change to price you can refresh this table.