题解 | 查询培训指定课程的员工信息
查询培训指定课程的员工信息
https://www.nowcoder.com/practice/a0ef4574056e4a219ee7d651ba82efef
select
ct.staff_id,
st.staff_name
from
staff_tb st
left join cultivate_tb ct on st.staff_id = ct.staff_id
where
ct.course like '%course3%'
SELECT DISTINCT
st.staff_id,
st.staff_name
FROM
staff_tb st
INNER JOIN cultivate_tb ct
ON st.staff_id = ct.staff_id
WHERE
FIND_IN_SET('course3', ct.course) > 0;
这道 SQL 题非常典型,我们来 一步一步、清晰地讲解它的解题思路,包括:目的、逻辑、陷阱、优化建议 和 常见错误。
✅ 原始 SQL:
SELECT
ct.staff_id,
st.staff_name
FROM
staff_tb st
LEFT JOIN cultivate_tb ct ON st.staff_id = ct.staff_id
WHERE
ct.course LIKE '%course3%'
🧩 一、题目目标(我们要查什么?)
虽然没有明确说明表结构,但从字段名可以推断:
staff_tb:员工主表(员工 ID + 姓名)cultivate_tb:培训记录表(员工 ID + 所选课程,可能是逗号分隔的字符串)
👉 目标是:找出所有“报了 course3” 的员工的 ID 和姓名。
🔍 二、逐句解析 SQL
1. SELECT ct.staff_id, st.staff_name
- 返回两个字段: ct.staff_id:来自培训表的员工 IDst.staff_name:来自员工表的姓名
⚠️ 注意:这里用的是
ct.staff_id而不是st.staff_id—— 如果ct中为 NULL,会显示 NULL,但其实应该一样。
✅ 更推荐写成 st.staff_id,因为主表更可靠。
2. FROM staff_tb st LEFT JOIN cultivate_tb ct ON st.staff_id = ct.staff_id
看起来是想从员工表出发,关联培训记录。
但是……
🔴 用了 LEFT JOIN 却在 WHERE 中对右表过滤!这是一个经典错误!
❌ 问题来了:
LEFT JOIN cultivate_tb ct ... WHERE ct.course LIKE '%course3%'
👉 这个 WHERE 条件会 过滤掉 ct.course 不包含 'course3' 或为 NULL 的记录
→ 实际上把 LEFT JOIN 变成了 INNER JOIN 效果!
🔄 对比一下:
| ❌ 破坏了 LEFT 的意义,只保留匹配项 |
| ✅ 才能保留左表全部 |
3. WHERE ct.course LIKE '%course3%'
- 使用
LIKE '%course3%'匹配课程字段中是否包含'course3' - 适用于
course字段存储的是类似'course1,course2,course3'这样的字符串
📌 优点:简单直接
⚠️ 缺点:可能误匹配!
比如:
'course3'✔️ 正确匹配'course33'❌ 也会被匹配到!(因为包含 'course3')'advanced_course3_beginner'❌ 也可能误中
✅ 三、正确解法应该是?
✅ 推荐写法(避免 LEFT JOIN 被污染):
SELECT
st.staff_id,
st.staff_name
FROM
staff_tb st
INNER JOIN cultivate_tb ct
ON st.staff_id = ct.staff_id
AND ct.course LIKE '%course3%'
或者保持 LEFT JOIN 风格(不推荐,此处无意义):
-- 不推荐:多此一举
SELECT
st.staff_id,
st.staff_name
FROM
staff_tb st
LEFT JOIN cultivate_tb ct
ON st.staff_id = ct.staff_id
AND ct.course LIKE '%course3%'
WHERE
ct.staff_id IS NOT NULL; -- 手动筛选出有匹配的
👉 本质还是内连接,不如直接写 INNER JOIN
✅ 四、如何更精确匹配 'course3'?
当前用 LIKE '%course3%' 容易误判。
✅ 改进建议:
方法 1:使用 FIND_IN_SET(MySQL 推荐!)
SELECT
st.staff_id,
st.staff_name
FROM
staff_tb st
INNER JOIN cultivate_tb ct
ON st.staff_id = ct.staff_id
WHERE
FIND_IN_SET('course3', ct.course) > 0;
✔️ FIND_IN_SET('val', csv) 专门用于判断一个值是否在一个逗号分隔的字符串中
✔️ 要求格式严格:a,b,c,不能有空格
❗ 若有空格需先处理:REPLACE(ct.course, ' ', '')
方法 2:正则表达式(更灵活)
WHERE
ct.course REGEXP '(^|,)course3(,|$)'
解释:
(^|,)→ 开头或逗号开始course3→ 精确匹配(,|$)→ 后面是逗号或结束
✅ 可防止 course33 被误匹配
✅ 五、完整推荐版本(最终答案)
SELECT DISTINCT
st.staff_id,
st.staff_name
FROM
staff_tb st
INNER JOIN cultivate_tb ct
ON st.staff_id = ct.staff_id
WHERE
FIND_IN_SET('course3', ct.course) > 0;
📌 加 DISTINCT 是为了防止一人多次报名导致重复输出(如果业务允许重复则可不加)
✅ 六、常见错误总结
❌
| 把 LEFT 变成 INNER,失去意义 |
❌
| 会误匹配
,
等 |
❌ 不去重 | 同一人多条记录时重复出现 |
❌ 使用
而非
| 若右表为空会返回 NULL |
✅ 七、一句话总结解题思路
要查询“选修了某门课的员工”,应使用
INNER JOIN关联员工与课程表,并通过FIND_IN_SET或正则精确匹配课程名称,避免模糊搜索带来的误报,同时选择主表字段确保数据完整性。
👏 你已经学会了一类高频面试题:
“如何从一个逗号分隔的字段中查找某个值?”

查看7道真题和解析