Get top best score in Laravel - mysql

I have 2 tables:
user: id, name
score: id, user_id, point
Now I want to get 5 users name who have the best score but seem like it was wrong.
Here's my code:
public function getTop(){
$top = DB::table('score')
->select('user_id', DB::raw('COUNT(point)'))
->groupBy('user_id')
->orderBy(DB::raw('COUNT(point)'), 'DESC')
->take(5)
->get();
return view('home',compact('top'));
}

In your case Database query makes more senses.
Database query to get top 5 user_id with total score.
Join users table with that result.
$topResult = DB::table('users'
)->join(DB::raw('(SELECT user_id, SUM(point) as score FROM score GROUP BY user_id ORDER BY SUM(point) LIMIT 5) as top_scorer'), function($join) {
$join->on('top_scorer.user_id', '=','users.id');
})
->select(['users.*', 'top_scorer.score']) //Select fields you need.
->orderBy('top_scorer.score')
->get();

Try this.
DB::table('users')
->select(['users.id', DB::raw('MAX(sc.point) AS score')])
->join('score AS sc', 'sc.id', '=', 'users.id')
->groupBy('users.id')
->take(5)->get();

Related

Join and OrderBy within with laravel eloquent query

I want to display ordered list of stores based on cities from a brand.
This is the code I tried
$brand = Brand::where('slug','=',$slugurl)
->with(['stores' => function($q){
$q->where('status', 1)
->join('cities', function ($join){
$join->on('cities.id', '=', 'stores.city_id')->orderBy('cities.sort_number', 'DESC');
});
}])
->firstOrFail();
The relationship of the tables :
Brand hasMany Stores and Stores belongTo Cities
The listings results output is not ordered based on cities sort_number. Any idea how to achieve this ?
It is useless to order in join's closure.
You need to append the orderBy after join:
$brand = Brand::where('slug','=',$slugurl)
->with(['stores' => function($q){
$q->where('status', 1)
->join('cities', 'cities.id', '=', 'stores.city_id')
->orderBy('cities.sort_number', 'DESC');
}])
->firstOrFail();
This query convert to raw sql is:
select * from brands where slug = ? limit 1;
select * from stores
join cities on cities.id = stores.city_id
where status = 1 and stores.brand_id in (?)
order by cities.sort_number desc;

Convert Raw SQL query to Laravel DB Query

I have the following raw SQL query:
select a.id user_id, a.email_address, a.name_first, a.name_last, count(b.id) number_of_videos, sum(b.vimeo_duration) total_duration, sum(b.count_watched) total_playbacks
from users a,
videos b
where a.id = b.tutor_id
and a.email_address in ('candace_rennie#yahoo.com', 'tjm#hiltoncollege.com', 'matthewjameshenshall#gmail.com', 'nkululeko#syafunda.co.za', 'khulile#syafunda.co.za', 'nzakheni#syafunda.co.za')
group by a.id;
This correctly gets 6 rows from the database. I'm trying to convert this to a Laravel database query like so:
$totals = DB::table('users')
->select(DB::Raw('users.id as user_id'), 'users.email_address', 'users.name_first', 'users.name_last', DB::Raw('count(videos.id) as number_of_videos'), DB::Raw('sum(videos.vimeo_duration) as total_duration'), DB::Raw('sum(videos.count_watched) as total_playbacks'))
->join('videos', 'users.id', '=', 'videos.tutor_id')
->where('users.id', 'videos.tutor_id')
->whereIn('users.email_address', array('candace_rennie#yahoo.com', 'tjm#hiltoncollege.com', 'matthewjameshenshall#gmail.com', 'nkululeko#syafunda.co.za', 'khulile#syafunda.co.za', 'nzakheni#syafunda.co.za'))
->groupBy('users.id')
->get();
This however return 0 rows. Is there anything I'm missing?
It should be smth like below even tho groupBy user id does not help much as id is unique.
$aggregates = [
DB::raw('count(b.id) as number_of_videos'),
DB::raw('sum(b.vimeo_duration) as total_duration'),
DB::raw('sum(b.count_watched) as total_playbacks'),
];
$simpleSelects = ['users.email_address', users.id, 'users.name_first', 'users.name_last'];
$emails = ['candace_rennie#yahoo.com', 'tjm#hiltoncollege.com'....]
$users = Users::select(array_merge($simpleSelects, $aggregates))
->leftJoin('videos as b', function ($join) use ($emails) {
$join->on('b.tutor_id', 'a.id')
->whereIn('users.email_address', $emails);
})
->groupBy('users.id')
->get();
Try to remove this line:
->where('users.id', 'videos.tutor_id')
List item
after sql code convert into laravel
DB::select('posts.id','posts.title','posts.body')
->from('posts')
->where('posts.author_id', '=', 1)
->orderBy('posts.published_at', 'DESC')
->limit(10)
->get();

How to convert mysql query to laravel query builder?

I have 2 tables and in first comments and article id, in second article title, id , category of article. I want has a title of article which has the most comments.
SELECT comments.article_id, news.title, news.category_id,
COUNT(comments.id) as counts
FROM comments
JOIN news ON news.id = comments.article_id
GROUP BY(article_id)
ORDER BY counts DESC
LIMIT 3
I tried this:
$articles = DB::table('comments')
->join('news', 'news.id', '=', ' comments.article_id')
->select(comments.article_id', 'news.title', ' news.category_id')
->count('comments.id')
->groupBy('article_id')
->orderBy(DB::raw('count(comments.id)', 'desc')
->limit(3)
->get();
But had:
Call to a member function groupBy() on integer
You are using a "finisher", which means ->count('comments.id') does not return an instance of QueryBuilder anymore but a regular type (integer).
As integers in PHP are not classes, you are trying to perform a method on an non-class, which led to display this error message.
You surely know others finishers like ->sum(), ->all(), ->get(), ...
Just remove your line ->count('comments.id') and you will be good to go:
$articles = DB::table('comments')
->join('news', 'news.id', '=', ' comments.article_id')
->select('comments.article_id', 'news.title', ' news.category_id')
->groupBy('article_id')
->orderBy(DB::raw('count(comments.id)', 'desc')
->limit(3)
->get();
DB::table('comments')
->join('news', 'news.id', '=', ' comments.article_id')
->selectRaw('comments.article_id', 'news.title', ' news.category_id', 'count(comments.id) as countsxyz')
->groupBy('article_id')
->orderBy(DB::raw('countsxyz'), 'desc')
->limit(3)
->get();
try this and let me know if you still face any issue.

Which laravel query to use to sort top entries according to related table

I have two models: posts and likes. Posts and likes have one-to-many relationship (so, one post has many likes). Likes model has also an isActive field which shows liking is active or passive.
I want to get (sort) top 5 posts which had received maximum "active" likes (only likes whose isActive field is true would be considered).
Which Laravel query could give me the result?
My question is sorting the post not only according to a field of a related model but also count of entries in the related table.
This is the query:
$posts = Post::selectRaw('posts.*, count(likings.id) as likes_count')
->leftJoin('likings', function ($join) {
$join->on('likings.post_id', '=', 'posts.id')
->where('likings.isActive', '=', 1);
})
->groupBy('posts.id')
->orderBy('likes_count', 'desc')
->take(5)
->get();
And this is the error:
SQLSTATE[42000]: Syntax error or access violation: 1055 'database.posts.user_id' isn't in GROUP BY
(SQL: select posts.*, count(likings.id) as likes_count from 'posts' left join 'likings' on 'likings'.'post_id' = 'posts'.'id' and 'likings'.'isActive' = 1 group by 'posts'.'id' order by 'likes_count' desc limit 5)
or just exequte this query
Post::with(['likes' => function ($query){
$query->where('active', 1);
}]);
and sort it by php if its too hard in mysql. For ex some PostTransformer class
Post::selectRaw('posts.*, count(likes.id) as likes_count')
->leftJoin('likes', function ($join) {
$join->on('likes.post_id', '=', 'posts.id')
->where('likes.is_active', '=', 1);
})
->groupBy('posts.id')
->orderBy('likes_count', 'desc')
->take(5)
->get();
or subselect:
Post::select('*')->selectSub(function ($q) {
$q->from('likes')
->whereRaw('likes.post_id = posts.id')
->where('is_active', 1)
->selectRaw('count(*)');
}, 'likes_count')
->orderBy('likes_count', 'desc')
->take(5)
->get();
Post::join(DB::raw('(select post_id, count(post_id) as number from likes) as likes_count ON posts.id = likes_count.post_id where likes_count.active = 1'), null)->orderBy('likes_count.number', 'desc')->limit(5);
I wrote that without checking this out, so don't hate

Laravel join with 3 Tables

I am building a Twitter-like app. There is a Feed in which I want to only show posts of Users who I follow.
I tried everything with joins, but nothing seems to work.
I have 3 tables: Users, Followers, Shares
The Tables look like this:
Users: id
Followers: user_id, follower_id
Shares: user_id
What I need to get is "ALL Shares WHERE share.user_id = followers.follower_id"
"ANDWHERE followers.user_id = users.id"
Assume, the users.id is 3, I tried this:
$shares = DB::table('shares')
->leftjoin('followers', 'shares.user_id', '=', 'followers.follower_id')
->leftjoin('users', 'followers.user_id', '=', 'users.id')
->where('users.id', 3)
->where('shares.user_id', 'followers.follower_id')
->get();
But it doesnt work.
Any help is appreciated :)
I believe your join is wrong:
$shares = DB::table('shares')
->join('users', 'users.id', '=', 'shares.user_id')
->join('followers', 'followers.user_id', '=', 'users.id')
->where('followers.follower_id', '=', 3)
->get();
I also suggest you to name your table as follows instead, it feels a bit more natural to say user has many followers through follows and user has many followees through follows.
Example
$shares = DB::table('shares')
->join('users', 'users.id', '=', 'shares.user_id')
->join('follows', 'follows.user_id', '=', 'users.id')
->where('follows.follower_id', '=', 3)
->get();
Model approach
I didn't realize you were using DB:: queries and not models. So I'm fixing the answer and providing a lot more clarity. I suggest you use models, it's a lot easier for those beginning with the framework and specially SQL.
Example of models:
class User extends Model {
public function shares() {
return $this->hasMany('Share');
}
public function followers() {
return $this->belongsToMany('User', 'follows', 'user_id', 'follower_id');
}
public function followees() {
return $this->belongsToMany('User', 'follows', 'follower_id', 'user_id');
}
}
class Share extends Model {
public function user() {
return $this->belongsTo('User');
}
}
Example of Model usage:
$my = User::find('my_id');
// Retrieves all shares by users that I follow
// eager loading the "owner" of the share
$shares = Share::with('user')
->join('follows', 'follows.user_id', '=', 'shares.user_id')
->where('follows.follower_id', '=', $my->id)
->get('shares.*'); // Notice the shares.* here
// prints the username of the person who shared something
foreach ($shares as $share) {
echo $share->user->username;
}
// Retrieves all users I'm following
$my->followees;
// Retrieves all users that follows me
$my->followers;
In terms of general MySQL syntax, this is best written:
SELECT * FROM USER a JOIN FOLLOWERS b ON (a.id = b.user_id) JOIN SHARES c on (b.follower_id = c.user_id) WHERE a.id = 3
will return a data set of all followers and their respective shares.
I believe you would want the following in Laravel
DB::table('USER')
->join('FOLLOWERS', 'USER.id', '=', 'FOLLOWERS.user_id')
->join('SHARES', 'FOLLOWERS.follower_id', '=', 'SHARES.user_id')
->where('USER.id', 3)
->get();
Instead of
->where('shares.user_id', 'followers.follower_id')
It should be
->whereRaw('shares.user_id=followers.follower_id')
because on the original example the 'followers.follower_id' is interpreted as a string.
$data[shares] = DB::table('shares')
->leftjoin('followers', 'shares.user_id', '=', 'followers.follower_id')
->leftjoin('users', 'users.id', '=', 'users.id')
->where('users.id','=', 3)
->get();
to see results.
print_r($data[shares]);die;
for other query Simply give discription of your table
First of all, go through users table and join it with followers table, and then with share table to get corresponding shares data of only followers. Here is the code
$shares = DB::table('users')
->leftjoin('followers', 'users.user_id', '=', 'followers.follower_id')
->leftjoin('shares', 'shares.user_id', '=', 'users.id')
->where('users.id', 3)
->get();