Duplicate rows with multiple join - php

I'm using this code to join two table on contents table then group by user
when I join only analytics table the result is correct also the same wehn joining only reactions table
but both table is causing wrong result in sum and count
->where('users.type_id', 2)
->leftJoin('contents', 'users.id', '=', 'contents.instructor_id')
->leftJoin('analytics', 'contents.id', '=', 'analytics.content_id')
->leftJoin('reactions', 'contents.id', '=', 'reactions.content_id')
->selectRaw('
users.id as id,
concat(users.name, "-", users.last_name) as name,
sum(analytics.total_watched) as sum_watched,
count(analytics.id) as times_watched,
sum(analytics.completed=1) as completed_video,
sum(reactions.reaction_type="love") as love,
sum(reactions.reaction_type="happy") as happy,
sum(reactions.reaction_type="thinking") as thinking,
sum(reactions.reaction_type="sad") as sad,
sum(reactions.reaction_type="angry") as angry
')
->groupBy('users.id')
->limit(10)
->get();

Related

How to select from a table based on another table's values Eloquent?

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

Three join and groupby ln laravel 5.4

Hello I am new with laravel and I need to do two join between three tables then group by and count in another table then join the result of the group by with the two join result.I try to use two query the first one for the two join and the second query for the group by but i don't know how to join the two query.
This is my first query three tables: members, members_courses_assign and courses
$temp = DB::table('members')
->join('members_courses_assign', 'members.externalPersonKey', '=', 'members_courses_assign.externalPersonKey')
->join('courses', 'members_courses_assign.referenceNumber', '=', 'courses.referenceNumber')->where(['courses.termkey'=>$termK,'members_courses_assign.termkey'=>$termK])->get();
This is my second query
$count= DB::table('files')
->select('referenceNumber', DB::raw('count(*) as total'))
->where(['termkey'=>$termK])
->groupBy('referenceNumber')
->get();
Then i need to join the result of the first with the second, I try to join the 4 table first but the 4th table 'files' will ambiguity because the 'referenceNumber' is'not unique in the 'files' table.
If I understand what you are trying to do, using join() with the 'count' subquery as the first argument, and passing a Closure as the second argument specifying the link between your main query and the subquery should work.
$temp = DB::table('members')
->join('members_courses_assign', 'members.externalPersonKey', '=', 'members_courses_assign.externalPersonKey')
->join('courses', 'members_courses_assign.referenceNumber', '=', 'courses.referenceNumber')
->join(DB::raw('(SELECT COUNT(*) AS count, referenceNumber FROM files WHERE termkey='.$termK.' GROUP BY referenceNumber) FileCount'), function($join)
{
$join->on('courses.referenceNumber', '=', 'FileCount.referenceNumber');
})
->where(['courses.termkey'=>$termK,'members_courses_assign.termkey'=>$termK])
->get();

Laravel - getting the count from two pivot tables as one number

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();

Laravel - Getting data from few tables (joining and ordering)

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();

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