-- 按性别分组,统计人数并筛选人数大于 6 的组SELECT gender, COUNT(*) AS num
FROM student
GROUPBY gender
HAVING num >6;
字段拼接:GROUP_CONCAT 可将组内多个值合并为一个字符串。
SELECT gender, GROUP_CONCAT(age) AS ages FROM student GROUPBY gender;
联表查询
当数据分散在多表中时,需要通过连接操作整合信息。主要有三种方式:
INNER JOIN:仅返回两表匹配的记录。
LEFT JOIN:保留左表所有记录,右表无匹配则为 NULL。
RIGHT JOIN:保留右表所有记录,左表无匹配则为 NULL。
-- 左连接:保留所有课程,即使没有对应教师SELECT c.cid FROM course c LEFTJOIN teacher t ON c.teacher_id = t.tid;
-- 内连接:只查询有授课教师的课程SELECT c.cid FROM course c INNERJOIN teacher t ON c.teacher_id = t.tid;
子查询与正则
子查询允许在一个查询中嵌套另一个查询,常用于复杂逻辑判断。
单行子查询:返回单个值,用于比较。
-- 查询谢小二老师所授的所有课程SELECT*FROM course WHERE teacher_id = (SELECT tid FROM teacher WHERE tname ='谢小二老师');
多行子查询:返回多行,常用 IN 或 EXISTS。
-- 查询学过特定课程的学生的学号SELECT*FROM student WHERE class_id IN (SELECT cid FROM course WHERE teacher_id =2);
FROM 子句中的子查询:将子查询结果视为临时表。
SELECT s.sid, s.sname
FROM student s
JOIN (SELECT student_id FROM score WHERE course_id IN (1, 2)) AS temp
ON s.sid = temp.student_id;
正则表达式:REGEXP 提供更灵活的匹配规则,如 ^ 开头,. 任意字符等。
-- 查询姓名为'谢'开头的教师SELECT*FROM teacher WHERE tname REGEXP '^谢';
SELECT student_id, AVG(num) AS avg_num
FROM score
GROUPBY student_id
HAVING avg_num >60;
2. 查询 C++ 课程比数据库课程成绩高的学生学号
思路:分别查出两门课的成绩作为临时表,然后关联对比。
SELECT A.student_id
FROM (
SELECT student_id, num FROM score WHERE course_id = (SELECT cid FROM course WHERE cname ='c++')
) AS A
INNERJOIN (
SELECT student_id, num FROM score WHERE course_id = (SELECT cid FROM course WHERE cname ='数据库')
) AS B ON A.student_id = B.student_id
WHERE A.num > B.num;
SELECT sid AS'学号', sname AS'姓名'FROM student
WHERE sid NOTIN (
SELECTDISTINCT sc.student_id
FROM score sc
JOIN course c ON sc.course_id = c.cid
JOIN teacher t ON c.teacher_id = t.tid
WHERE t.tname ='谢小二'
);
5. 查询学过课程编号为 1 并且也学过课程编号为 2 的同学
思路:统计每个学生选的课程数,要求同时选了这两门(即 distinct count = 2)。
SELECT s.sid AS'学号', s.sname AS'姓名'FROM student s
JOIN score sc ON s.sid = sc.student_id
WHERE sc.course_id IN (1, 2)
GROUPBY s.sid, s.sname
HAVINGCOUNT(DISTINCT sc.course_id) =2;
6. 查询学过某老师所有课的同学
思路:先算出该老师教了多少门课,再筛选出学生学过的数量等于该总数的记录。
SELECT s.sid AS'学号', s.sname AS'姓名'FROM student s
JOIN score sc ON s.sid = sc.student_id
JOIN course c ON sc.course_id = c.cid
JOIN teacher t ON c.teacher_id = t.tid
WHERE t.tname ='谢小二'GROUPBY s.sid, s.sname
HAVINGCOUNT(DISTINCT sc.course_id) = (
SELECTCOUNT(cid) FROM course WHERE teacher_id = (SELECT tid FROM teacher WHERE tname ='谢小二')
);
7. 查询有课程成绩小于 60 分的学生
SELECTDISTINCT s.sid AS'学号', s.sname AS'姓名'FROM student s
JOIN score sc ON s.sid = sc.student_id
WHERE sc.num <60;
8. 查询没有学全所有课的同学
思路:总课程数减去学生选课数,差值大于 0 即为未学全。
SELECT s.sid AS'学号', s.sname AS'姓名'FROM student s
LEFTJOIN score sc ON s.sid = sc.student_id
GROUPBY s.sid, s.sname
HAVINGCOUNT(DISTINCT sc.course_id) < (SELECTCOUNT(cid) FROM course);
9. 查询至少有一门课与学号为 1 的同学所学相同的同学
SELECTDISTINCT s.sid AS'学号', s.sname AS'姓名'FROM student s
JOIN score sc ON s.sid = sc.student_id
WHERE sc.course_id IN (SELECT course_id FROM score WHERE student_id =1)
AND s.sid <>1;
10. 查询至少学过学号为 1 同学所有课的其他同学
思路:类似第 6 题,对比的是学号 1 的课程总数。
SELECT s.sid AS'学号', s.sname AS'姓名'FROM student s
JOIN score sc ON s.sid = sc.student_id
WHERE s.sid <>1AND sc.course_id IN (SELECT course_id FROM score WHERE student_id =1)
GROUPBY s.sid, s.sname
HAVINGCOUNT(DISTINCT sc.course_id) = (
SELECTCOUNT(course_id) FROM score WHERE student_id =1
);