[英]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.