繁体   English   中英

查询效率 -> 使用连接或联合合并 2 个查询

[英]Query efficiency -> merge 2 queries with a join or union

我需要一些认真的帮助/指导。 我有两张桌子:

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

我需要两个数组:

在请求的 serviceDate 上注册的所有学生('serviceDate 在他们的 enter_date 和 exit_date 之间),在请求的 serviceDate 上没有请求的 mealType 的 meal_type_id。

所有在请求的“serviceDate”上注册的学生(“serviceDate 在他们的 enter_date 和 exit_date 之间)确实在请求的 serviceDate 上具有请求的 mealType 的meal_type_id。

我得到它与以下工作:

 '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));
        });        

当我为拥有 400 多名学生左右的数据库项目播种时,速度真的很慢。 我很确定我需要压缩上面的两个查询,但我无法弄清楚逻辑。

下面是一个尝试,但它给了我一个错误“方法 Illuminate\Database\Eloquent\Collection::getBindings 不存在”。

$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,
                ]),    

如果您愿意,我将非常感谢任何见解/帮助/指针/提示。

如果您使用集合,我认为您的问题非常简单

//关系名称应该是餐而不是学生餐,因为一个学生有很多学生餐是多余的

$students = Student::with([
    'meals' => function ($query) use ($request) {
        $query->where('date_served', $request['serviceDate']);
    }
])
    ->where('site_id', $request->user()->site_id)
    ->where('enter_date', '<=', $request['serviceDate'])
    ->where('exit_date', '>=', $request['serviceDate'])
    ->get();

至此,所有学生的请求 serviceDate 在 enter_date 和 exit_date 之间,并且属于当前用户的同一个 site_id(延迟加载属于请求 serviceDate 的学生的所有餐点),所以,你要做的就是将它们分布在两个不同的集合中。

//Students with requested meal type
$swrmt = collect();
//Students without requested meal type
$swtrmt = collect();

foreach ($students as $student) {
    //If student contains at least one meal with the requested mealType
    if ($student->contains('meals.meal_type_id', $request['mealType'])) {
        $swrmt->push($student);
    } ese {
        $swtrmt->push($student);
    }
}

因此,您只有一个查询,并且只需要担心结果是否大于 2000 名学生,如果发生这种情况,则需要使用 2000 块更改 with 以防止限制参数查询错误。 (对不起,如果有任何类型错误,我把所有这些都写在我的手机上),并且不要忘记在主查询中添加您的姓名过滤器,与您已经使用的相同。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM