I'm creating a ranking of players badges and I'm stuck with db query.
Tables:
user(id), club(id), club_user(user_id, club_id), badges(user_id)
I would like to get list of all users from specified club (for example club.id = 1) with amount of badges they have. Results should be ordered by number of badges.
How to create that kind of db query? Is it possible with Eloquent?
Should it be made with db::table and join?
Table user
id|name
1|John
2|Robert
3|Kate
Table club
id|name
1|Sunshine Club
2|Example Club
Table club_user
user_id|club_id
1|1
2|1
3|2
Table bagdes
id|name|user_id|club_id
1|Champion|1|1
2|Some badge|1|1
3|example|2|1
4|Gold Badge|3|2
so if I would like to get ranking of users from club 1, ordered by badge count.
I should get:
name|number of badges
John|2 (badges)
Robert|1 (badge)
Kate is not it this club.
Try this
select user.name ,user.id as userid , (select count(bagdes.id) from
bagdes where user_id= userid)
as total_badges from user inner join club_user on
user.id = club_user.user_id where club_user.club_id = 1
You will get your output.
Finally I made it with this DB::table query:
$users = DB::table('users')
->select('users.name', DB::raw('count(*) as badges'))
->join('badges', 'badges.user_id', '=', 'users.id')
->where('badges.club_id', 1)
->groupby('users.id')
->orderBy('badges', 'DESC')
->get();
Related
I have 3 tables users and meeting table and user_role. In user table I have user_name and user_role fields
and in meeting table I have the column meeting_id assigned_username and created_by_user_name fields and In user_roles table have id and role .
users
user_name role
a 1
b 2
c 3
meeting table
meeting_id assigned_username created_by_user_name
m1 a b
m2 b -
m3 b a
user_roles
id user_role
1 role1
2 role2
3 role3
I want to get the assigned_user_name's user_role and created_by_user_name's user_role in single query. I have tried as
$user=DB::table('meeting')
->leftjoin('users','users.user_name','=','meeting_after_validation.assigned_user_name')
->leftjoin('users as ca','ca.user_name'),'=','meeting_after_validation.created_by_name')
->leftjoin('user_roles','users.user_role','=','user_roles.id')
->leftjoin('user_roles as carole','ca.user_role','=','carole.id')
->whereIn('carole.is',['1','2'])
->select('users.user_name','user_roles.role','carole.role')->toArray();
but getting
Call to a member function whereIn() on array
how to get role of assigned_user_name and created_by_user_name.
You must use get() before you can use toArray() if you want to get the values as an array.
Also, there may be a typo for your whereIn, should it be carole.id?
Here is what the query could look like in SQL:
SELECT
meeting.meeting_id,
users_assigned.user_name as assigned_user,
role_assigned.user_role as assigned_user_role,
users_created.user_name as created_user,
role_created.user_role as created_user_role
FROM meeting
LEFT JOIN users as users_assigned ON meeting.assigned_username = users_assigned.user_name
LEFT JOIN user_roles as role_assigned ON users_assigned.role = role_assigned.id
LEFT JOIN users as users_created ON meeting.created_by_user_name = users_created.user_name
LEFT JOIN user_roles as role_created ON users_created.role = user_roles.id
WHERE role_assigned.id IN (1, 2)
And in Laravel query builder:
$user = DB::table('meeting')
->select([
'meeting.meeting_id',
'users_assigned.user_name as assigned_user',
'role_assigned.user_role as assigned_user_role',
'users_created.user_name as created_user',
'role_created.user_role as created_user_role',
])
->leftJoin('users as users_assigned', 'meeting.assigned_username', '=', 'users_assigned.user_name')
->leftJoin('user_roles as role_assigned', 'users_assigned.role', '=', 'role_assigned.id')
->leftJoin('users as users_created', 'meeting.created_by_user_name', '=', 'users_created.user_name')
->leftJoin('user_roles as role_created', 'users_created.role', '=', 'user_roles.id')
->whereIn('role_assigned.id', [1, 2])
->get()
->toArray();
I am trying to get the data on some students that are still active. Even tho I have data from inactive students in the same table.
This is the StudentAttendance
This is the StudentClass
This is the Eloquent query that I came up with:
StudentAttendance::
select('student_classes.active', 'student_attendances.student_id', 'student_attendances.classroom_id', 'classrooms.classroom', 'attendance_rules.option')
->join('classrooms', 'classrooms.id', '=', 'student_attendances.classroom_id')
->join('attendance_rules','attendance_rules.id', '=', 'student_attendances.attendance_id')
->join('student_classes', 'student_attendances.student_id', '=', 'student_classes.student_id')
->where('attendance_date', date("Y-m-d"))
->orderBy('classrooms.classroom', 'ASC')
->get();
SQL:
select `student_classes`.`active`, `student_attendances`.`student_id`, `student_attendances`.`classroom_id`, `classrooms`.`classroom`, `attendance_rules`.`option`
from `student_attendances`
inner join `classrooms` on `classrooms`.`id` = `student_attendances`.`classroom_id`
inner join `attendance_rules` on `attendance_rules`.`id` = `student_attendances`.`attendance_id`
inner join `student_classes` on `student_attendances`.`student_id` = `student_classes`.`student_id`
where `attendance_date` = '2020-02-11'
order by `classrooms`.`classroom` asc
Now my Eloquent query results into this:
As you can see the student_id 22 with the classroom_id of 2 is inactive but it appears to be inactive once and the rest active. If I remove the student_classes join I won't get all the repeated results.
The goal is to display all the attendances of today where the student is active (active=1) in the StudentClass even if I query in the StudentAttendance.
You will want to scope your join to student_classes to only look at active records.
You can do this by using a callback in your join method:
->join('student_classes', function ($join) {
$join->on('student_attendances.student_id', '=', 'student_classes.student_id')
->on('student_classes.classroom_id', '=', 'student_attendances.classroom_id')
->where('student_classes.active', 1);
})
This is covered under the 'Advanced Join Clauses' in the Query Builder docs - https://laravel.com/docs/5.8/queries#joins
Good evening my coder friends,
As the title of this Question says, i have a little bit complex mysql query that i am trying to use query builder in Laravel to write it down, but every time i try to write it i stop when reach to the subquery. i will write down the query and also will let you know what the query will do .
SELECT
brands.name_en as brand_name_en,
brands.name_ar as brand_name_ar,
brands.brand_url as brand_url,
brands.description_ar as description_ar,
brands.description_en as description_en,
categories.name_en as category_name_en,
categories.name_ar as category_name_ar
FROM
brands
INNER JOIN categories ON brands.category_id = categories.id
WHERE
(brands.status = "1")
AND
(
brands.id IN (
SELECT
distinct(items.brand_id)
FROM
items
WHERE
items.in_stock = "1"
GROUP BY
(items.brand_id)
)
)
The query explanation :
I have three tables :
Brand (id,name,category_id)
Categories (id,name,brand_id)
Items (id,brand_id,in_stock,sold_date)
Now i want to do the following :
i want to retrieve (brand name , and the category name ) and sort them based on the highest sales in the last month
This is example on the tables with data in them :
Brands Table
------------
id name category_id
1 googleplay 1
Categories Table
--------------------------
id name brand_id
1 cards 1
items Table
-----------
id brand_id in_stock selling_date
1 1 0 null
1 1 1 2017-02-02 04:04:49
Been trying for almost 2 days but no luck as its really complicated when it reaches the subquery part .
Really hope to find help from you guys . and let me know if you guys need more explanation please , i might forgot something while writing the questions .
Thank you in advance.
If you change your sql a little, you can make it with inner joins:
SELECT brands.name, categories.name
FROM brands
INNER JOIN categories ON brands.category_id = categories.id
INNER JOIN items ON categories.id = items.brand_id
WHERE brands.status = 1 AND items.in_stock = 1
Translating this to Laravel is simple:
\DB::table('brands')
->join('categories', 'brands.category_id', '=', 'categories.id')
->join('items', 'brands.id', '=', 'items.brand_id')
->select('brands.name as brand', 'categories.name as category')
->where('brands.status', 1)
->where('items.in_stock', 1)
->get();
Conceptually speaking, How about we select the items from the item tables for the last month, sort them and fetch the brand and category via a join on that.
It can be written in a single query as follows:
DB::table('items')
->join('brands', 'items.brand_id', '=', 'brands.id')
->join('categories', 'brands.category_id', '=', 'categories.id')
->select('brands.name as brand', 'categories.name as category')
->where('brands.status', 1) // as per your query
->whereRaw(YEAR(items.selling_date) = YEAR(CURRENT_DATE - INTERVAL 1 MONTH)) // year condition
->whereRaw(MONTH(date_created) = MONTH(CURRENT_DATE - INTERVAL 1 MONTH)) // last month condition
->orderBy('items.in_stock', 'desc') // orderBy the sales
->distinct() // Since you only require brand names and category names, choosing distinct will avoid the need of the GROUP BY eliminating the multiple occurances of a brand in the items table
->get()
I haven't tried running this query, but hope it helps. If I have misunderstood the question feel free to correct me.
I have a table with articles and two pivot tables views and votes for articles that have columns article_id and user_id. For articles I have a column publish where I check if the article is published. I need to make a query by popularity, where I get all the published articles with their count from both pivot tables, where each vote from the table votes counts as 3, and each count from the table views counts as 1. Not sure how to do this, I previously had a query where I was getting published articles with their count of only votes, but I was only getting the articles that had some votes, and not the ones that were published but had no votes. And in the new query I need to add views as well, and change the logic for counting as well as including the articles that are published and not views and order them by their count from these two pivot tables.
So, the wanted output would something like this:
[{"id":117,"popularityCount":17},{"id":118,"popularityCount":15},{"id":121,"popularityCount":13}]
This was the query, but that is not what I need anymore:
$articles = DB::table('articles')
->select([DB::raw('articles.id'), DB::raw('COUNT(*) as "votes"')])
->join('votes', 'article_id', '=', 'articles.id')
->where('articles.publish', 1)
->groupBy('votes.article_id')
->orderBy('votes', 'desc')
->get();
return $articles;
This is what worked for me in the end if anyone will need it in the future!
$result = Article::select('articles.*', 'v.vote_count', 'vw.view_count')
->where('publish', 1)
->leftJoin(DB::raw('(SELECT votes.article_id, COUNT(*) AS vote_count FROM votes GROUP BY votes.article_id) v'), 'v.article_id', '=', 'articles.id')
->leftJoin(DB::raw('(SELECT views.article_id, COUNT(*) AS view_count FROM views GROUP BY views.article_id) vw'), 'vw.article_id', '=', 'articles.id')
->orderByRaw('(v.vote_count * 3) + vw.view_count DESC')
->where('created_at', '>', $date->format('Y-m-d') . ' 00:00:00')
->get();
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();