Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

mpk123's avatar

HELP with join/union query

Hi there -

I need some serious help/direction. I have two tables:

students 
-id
-site_id
-name
-enter_date
-exit_date
student_meals
-id
-site_id
-student_id
-meal_type_id (1, 2, or 3)
-date_served

I need two arrays:

All students enrolled on the requested 'serviceDate' ('serviceDate is between their enter_date and exit_date) that DO NOT have a meal_type_id of the requested mealType on the rquested serviceDate.

All students enrolled on the requested 'serviceDate' ('serviceDate is between their enter_date and exit_date) that DO have a meal_type_id of the requested mealType on the requested serviceDate.

I got it to work with the following:

 'unservedStudents' => Auth::user()->site 
                ->students()
                ->where('enter_date', '<=',Request::only( 'serviceDate') )
                ->where('exit_date', '>=',Request::only( 'serviceDate') )
                ->OrderByName()
                ->filter(Request::only('search', 'serviceDate', 'mealType'))
                ->get()
                ->map(fn ($students) => [
                    'id' => $students->id,
                    'name' => $students->name,
                ]),    
                
          'servedStudents' => Auth::user()->site
                ->student_meals()
                ->with('student')
                ->where('meal_type_id', Request::only( 'mealType'))
                ->where('date_served', Request::only( 'serviceDate'))
                ->orderBy('created_at', 'DESC')
                ->get()
                ->map(fn ($served_students) => [
                    'id' => $served_students->id,
                    'student' => $served_students->student ? $served_students->student->only('id','name') : null,
                ]),

//Filter for students

 public function scopeFilter($query, array $filters)
    {
        $mealType = $filters['mealType'] ?? null;
        $serviceDate = $filters['serviceDate'] ?? null;
        $search = $filters['search'] ?? null;

$query
            ->when($search, function ($query) use ($search) { 
                $query->where( fn ($query) =>
                    $query->where('first_name', 'like', '%'.$search.'%')
                   
        })
            ->when( $mealType, function ($query) use ($mealType, $serviceDate) {
                $query->whereDoesntHave('student_meals', fn ($query) => 
                    $query->where('meal_type_id', $mealType )
                        ->where('date_served', $serviceDate));
        });        

When I seeded my database ites that have more than 400 students or so gets really slow. I'm pretty sure I need to condense the two queries above, but I can't figure out the logic.

Below is an attempt, but it gives me an error 'Method Illuminate\Database\Eloquent\Collection::getBindings does not exist'.

$students  = Auth::user()->site 
                ->students()
                ->join('student_meals as m', 'm.student_id', '=', 'students.id')//this is my attempt to get the same columns as the table to union....
                ->where('enter_date', '<=',Request::only( 'serviceDate') )
                ->where('exit_date', '>=',Request::only( 'serviceDate') )
                ->where('date_served', '=',Request::only( 'serviceDate') )
                ->filter(Request::only('search', 'serviceDate', 'grade', 'hr'))
                ->select('students.id as studentId', 'first_name',  'students.site_id as siteId',  'm.id as mealId', 'm.meal_type_id', )
                ->get()
                ->map(fn ($students) => [
                    'id' => $students->studentId,
                    'name' => $students->first_name,
                    'siteId' => $students->site_id,
                    'mealId' => $students->mealId,
                    'mealType' => $students->meal_type_id,
                ]),    


            'student_meals' => Auth::user()->site 
                ->student_meals()
                ->join('students as s', 's.id', '=', 'student_meals.student_id')
                ->where('date_served', '>=',Request::only( 'serviceDate') )
                ->where('meal_type_id', '>=',Request::only( 'mealType') )
                ->select('s.id as studentId', 'first_name',  
                's.site_id as siteId',  'student_meals.id as mealId', 'meal_type_id')
                ->union($students)
                ->map(fn ($students) => [
                    'id' => $students->studentId,
                    'name' => $students->first_name,
                    'siteId' => $students->site_id,
                    'mealId' => $students->mealId,
                    'mealType' => $students->meal_type_id,
                ]),    

If you're up for it, I'd really appreciate any insight/help/pointers/tips.

0 likes
1 reply
mpk123's avatar

I figureout the query with some help:https://stackoverflow.com/questions/72925441/query-efficiency-merge-2-queries-with-a-join-or-union/72926337#72926337

            'students' => Auth::user()->site 
                ->students()
                ->leftJoin('student_meals as m', function ($join) {
                    $join->on('m.student_id', '=', 'students.id')
                        ->where('date_served', Request::only( 'serviceDate') )
                        ->where('meal_type_id', Request::only( 'mealType'));
                    })
                ->where('enter_date', '<=',Request::only( 'serviceDate') )
                ->where('exit_date', '>=',Request::only( 'serviceDate') )
                ->OrderByName()
                ->filter(Request::only('search', 'serviceDate', 'grade', 'hr'))
                ->select('students.id as studentId', 'first_name', 'last_name', 'grade', 'hr', 'students.sfa_id as sfaId', 'students.site_id as siteId', 'sisId', 'm.id as mealId', 'm.meal_type_id', 'm.created_at as created_at', 'void')
                ->get()
                ->map(fn ($students) => [
                    'studentId' => $students->studentId,
                    'name' => $students->name,
                    'grade' => $students->grade,
                    'hr' => $students->hr,
                    'sfaId' => $students->sfaId,
                    'siteId' => $students->siteId,
                    'sisId' => $students->sisId,
                    'mealId' => $students->mealId,
                    'mealType' => $students->meal_type_id,
                    'created' => $students->created_at,
                    'voided' => $students->void
                ]),    

Please or to participate in this conversation.