Laravel中查询技能为用户技能子集的Job ID方法
实现Laravel中“适合我的职位”技能匹配功能
首先明确核心需求:找出所有职位技能集合是当前用户技能集合子集的Job ID,也就是职位要求的每一项技能,当前用户都具备,职位不能要求用户没有的技能。
先纠正你代码里的核心问题
你当前的代码逻辑搞反了:
- 你写的
COUNT(DISTINCT name) = ?是在统计「职位包含的用户技能数量等于用户技能总数」,这是找用户技能全包含在职位技能里的职位(用户技能是子集),和你的需求完全相反。 - 第二个
havingRaw的写法也有问题,NOT IN (?)无法直接绑定数组,会导致SQL语法错误。
优化后的实现方案
方案1:Eloquent关联写法(推荐,代码最简洁)
前提是你的Job模型和JobSkill模型已经建立关联:
在Job模型中添加关联方法:
public function skills() { return $this->hasMany(JobSkill::class, 'jobid'); }
然后直接用whereDoesntHave筛选出「没有任何超出用户技能的职位」:
$userId = \Auth::id(); // 快速获取用户技能名称数组 $userSkills = Skill::where('userid', $userId)->pluck('name')->toArray(); // 找出所有技能全在用户技能范围内的职位ID $validJobIds = Job::whereDoesntHave('skills', function($query) use ($userSkills) { // 排除有任何技能不在用户技能里的职位 $query->whereNotIn('name', $userSkills); })->pluck('id');
方案2:原生查询构建器写法
如果不想用模型关联,也可以用查询构建器直接处理:
$userId = \Auth::id(); $userSkills = Skill::where('userid', $userId)->pluck('name')->toArray(); // 先找出所有包含用户没有的技能的职位ID(这些是不符合的) $invalidJobIds = JobSkill::whereNotIn('name', $userSkills)->pluck('jobid')->toArray(); // 剩下的就是所有技能都在用户技能里的职位ID $validJobIds = JobSkill::select('jobid') ->whereNotIn('jobid', $invalidJobIds) ->groupBy('jobid') ->get();
方案3:分组统计写法
通过统计每个职位中「不在用户技能里的技能数量」来筛选:
$userId = \Auth::id(); $userSkills = Skill::where('userid', $userId)->pluck('name')->toArray(); $skillCount = count($userSkills); // 用户没有技能时直接返回空集合 if ($skillCount === 0) { $validJobIds = collect(); } else { // 把技能数组转成SQL能用的字符串格式 $skillStr = implode(',', array_map(fn($s) => "'{$s}'", $userSkills)); $validJobIds = JobSkill::select('jobid') ->groupBy('jobid') // 确保该职位没有任何技能不在用户技能范围内 ->havingRaw("SUM(CASE WHEN name NOT IN ({$skillStr}) THEN 1 ELSE 0 END) = 0") ->get(); }
额外优化:获取用户技能数组的简洁写法
你原来用循环转数组的方式可以简化成:
$userSkills = Skill::where('userid', $userId)->pluck('name')->toArray();
pluck('name')直接取出所有技能名称的集合,再转成数组即可,不用手动循环。
内容的提问来源于stack exchange,提问作者dacoder
相关产品推荐
相关产品推荐

