You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL多表查询:获取班级活跃课程完全匹配的学生姓名

解决精确匹配班级活跃课程的学生查询问题

这个精确匹配的需求其实核心要抓两个关键点:既要保证班级的所有活跃课程都在你传入的列表里,又要保证班级的活跃课程数量和传入列表的长度完全一致——缺了任何一个条件,都会出现你说的「把有额外课程的学生也返回」的问题。

我给你两种可行的SQL写法,你可以根据自己的习惯选择:

方法一:用分组聚合+HAVING子句筛选符合条件的班级

这种方法先通过子查询找出所有符合条件的班级,再关联学生表获取姓名,逻辑清晰且性能不错:

SELECT s.name AS student_name
FROM students s
INNER JOIN (
    -- 子查询:找出活跃课程恰好匹配传入列表的班级
    SELECT c.class_id
    FROM courses c
    WHERE c.active = TRUE -- 只考虑活跃课程
    GROUP BY c.class_id
    HAVING 
        -- 条件1:班级里没有不在传入列表中的活跃课程
        SUM(CASE WHEN c.name NOT IN ('foo', 'bar') THEN 1 ELSE 0 END) = 0
        -- 条件2:班级的活跃课程数量和传入列表的长度完全一致
        AND COUNT(*) = 2
) eligible_classes ON s.class_id = eligible_classes.class_id;

代码解释:

  • SUM(CASE...) = 0:遍历班级的每一门活跃课程,如果有课程不在传入列表里,就会累加1,最终总和为0就说明所有课程都在列表中。
  • COUNT(*) = 2:确保班级的活跃课程数量正好等于你传入的数组长度(这里是2,对应['foo','bar']),避免出现「班级包含传入的所有课程,但还多了其他课程」的情况。

方法二:用双重NOT EXISTS做存在性检查

这种写法逻辑更直观,适合喜欢用存在性判断的场景:

SELECT s.name AS student_name
FROM students s
WHERE EXISTS (
    SELECT 1
    FROM classes cls
    WHERE cls.id = s.class_id
    -- 先检查班级活跃课程数量和传入列表一致
    AND (SELECT COUNT(*) FROM courses c WHERE c.class_id = cls.id AND c.active = TRUE) = 2
    -- 再检查班级没有任何不在传入列表里的活跃课程
    AND NOT EXISTS (
        SELECT 1
        FROM courses c
        WHERE c.class_id = cls.id
          AND c.active = TRUE
          AND c.name NOT IN ('foo', 'bar')
    )
);

适配Ruby函数的安全写法

在Ruby里使用时,一定要注意避免SQL注入,不要直接把数组拼进SQL字符串,要用参数占位符:

def get_student_names_whose_courses_are(active_course_names)
  course_count = active_course_names.length
  # 用占位符?来传递参数,数据库驱动会自动处理数组和数值的转义
  sql = <<~SQL
    SELECT s.name AS student_name
    FROM students s
    INNER JOIN (
        SELECT c.class_id
        FROM courses c
        WHERE c.active = TRUE
        GROUP BY c.class_id
        HAVING 
            SUM(CASE WHEN c.name NOT IN (?) THEN 1 ELSE 0 END) = 0
            AND COUNT(*) = ?
    ) eligible_classes ON s.class_id = eligible_classes.class_id
  SQL

  # 假设你用ActiveRecord,用select_values获取所有学生姓名的数组
  ActiveRecord::Base.connection.select_values(sql, nil, [active_course_names, course_count])
end

这样不管你传入什么课程名称数组,都能安全且准确地返回符合条件的学生姓名啦。

内容的提问来源于stack exchange,提问作者Leem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:43:53