你必知必会的SQL面试题

写在前面的话

本文参考原博《走向面试之数据库基础:一、你必知必会的SQL语句练习-Part 1》和《走向面试之数据库基础:一、你必知必会的SQL语句练习-Part 2》进行练习,部分题目在不变化其练习目的的情况下进行了题意改动,并删除部分重复和无表的题目。

在此之前已练习完两遍并分别放在WizNote和Github,其中第二遍在Github上针对个人的sql弱项题目进行了更详细的说明(Github:MyTraining/sql),随着越来越熟练,本文作为第三次练习,部分重点题目的详细解析和想法在这里就没有具体描述,或许以后会补上,但是谁知道呢(摊手)。

涉及的表结构和测试数据

使用数据库软件直接导出的SQL(偷懒直接把Part1和Part2的导在一起的,因为表名各不相同所以这里并不影响练习使用),数据库是MySQL。


Part 1 练习题和参考解

(1)查询“001”课程比“002”课程成绩低的所有学生的学号、001学科成绩、002学科成绩
SELECT 
  s1.StudentNo,
  s1.score AS '001',
  s2.score AS '002'
FROM
  score s1,
  (
  SELECT
    *
  FROM
    score s
  WHERE
    s.CourseNo = 2
  ) s2
WHERE
  s1.CourseNo = 1
  AND
  s1.StudentNo = s2.StudentNo
  AND
  s1.score < s2.score
  ORDER BY s1.StudentNo

SELECT
  s1.StudentNo,
  s1.score AS '001',
  s2.score AS '002'
FROM 
  score s1, 
  score s2
WHERE 
  s1.CourseNo = 001 
  AND 
  s2.CourseNo = 002 
  AND 
  s1.StudentNo = s2.StudentNo
  AND
  s1.score < s2.score
  ORDER BY s1.StudentNo


(2)查询平均成绩大于60分的同学的学号和平均成绩

SELECT
  s1.StudentNo,
  AVG(s1.score)
FROM
  score s1
GROUP BY s1.StudentNo
HAVING AVG(s1.score)>60


(3)查询所有同学的学号、姓名、选课数、总成绩

SELECT
  s1.StudentNo,
  stu1.name,
  COUNT(*),
  SUM(s1.score)
FROM
  score s1,
  student stu1
WHERE
  s1.StudentNo = stu1.StudentNo
GROUP BY s1.StudentNo


(4)查询姓“李”的老师的个数

SELECT
  COUNT(*)
FROM
  teacher t1
WHERE
  t1.name like '李%'


(5)查询没学过“叶平”老师课的同学的学号、姓名

SELECT
  stu1.StudentNo,
  stu1.name
FROM
  student stu1
WHERE
  stu1.StudentNo NOT IN
  (
  SELECT DISTINCT
    s1.StudentNo
  FROM
    score s1,
    course c1,
    teacher t1
  WHERE
    s1.courseNo = c1.CourseNo
    AND
    c1.teacherNo = t1.teacherNo
    AND
    t1.name = '叶平'
  )

(6)查询学过“001”并且也学过编号“002”课程的同学的学号、姓名

-- 这个算法比普通的要有想法
SELECT
  s1.StudentNo,
  stu1.name
FROM
  score s1,
  student stu1
WHERE
  s1.StudentNo = stu1.StudentNo
  AND
  s1.CourseNo IN (1, 2)
GROUP BY s1.StudentNo
HAVING COUNT(*) = 2

SELECT
  s1.StudentNo,
  stu1.name
FROM
  score s1,
  student stu1
WHERE
  s1.StudentNo = stu1.StudentNo
  AND
  s1.CourseNo = 1
  AND
  s1.StudentNo IN
  (
  SELECT
    s2.StudentNo
  FROM
    score s2
  WHERE
    s2.CourseNo = 2
  )

(7)查询学过“叶平”老师所教的所有课的同学的学号、姓名

-- 利用主键值不相同,它们的和一定各不相同,叶平老师的课程的主键值和如果与学生所学的叶平老师的课程的主键值和相等,那么说明学了叶平老师所有课程
SELECT
  stu1.StudentNo,
  stu1.name
FROM
  score s1,
  student stu1,
  course c1,
  teacher t1
WHERE
  s1.StudentNo = stu1.StudentNo
  AND
  s1.CourseNo = c1.CourseNo
  AND
  c1.teacherNo = t1.teacherNo
  AND
  t1.name = '叶平'
GROUP BY s1.StudentNo
HAVING SUM(s1.CourseNo)=
(
SELECT
  SUM(c2.CourseNo)
FROM
  course c2,
  teacher t2
WHERE
  c2.teacherNo = t2.teacherNo
  AND
  t2.name = '叶平'
)

-- 如果学生学习叶平老师的课程数量,与叶平老师所教学课程的数量相同,那么说明该同学学了叶平老师的所有课程
SELECT
  stu1.StudentNo,
  stu1.name
FROM
  score s1,
  student stu1,
  course c1,
  teacher t1
WHERE
  s1.StudentNo = stu1.StudentNo
  AND
  s1.CourseNo = c1.CourseNo
  AND
  c1.teacherNo = t1.teacherNo
  AND
  t1.name = '叶平'
GROUP BY s1.StudentNo
HAVING COUNT(*) =
(
SELECT
  COUNT(*)
FROM
  course c2,
  teacher t2
WHERE
  c2.teacherNo = t2.teacherNo
  AND
  t2.name = '叶平' 
)

(8)查询课程编号“002”的成绩比课程编号“001”课程低的所有同学的学号、姓名
SELECT
  stu1.studentNo,
  stu1.name
FROM
  score s1,
  (
  SELECT
    s2.StudentNo,
    s2.score
  FROM
    score s2
  WHERE
    s2.CourseNo = 1
  ) t2,
  student stu1
WHERE
  s1.CourseNo = 2
  AND 
  s1.StudentNo = t2.StudentNo
  AND 
  s1.score < t2.score
  AND 
  s1.StudentNo = stu1.studentNo

(9)查询有课程成绩小于60分的同学的学号、姓名

SELECT DISTINCT
  s1.StudentNo,
  stu1.name
FROM
  score s1,
  student stu1
WHERE
  s1.StudentNo = stu1.studentNo
  AND
  s1.score < 60

(10)查询没有学全所有课的同学的学号、姓名

SELECT
  stu1.StudentNo,
  stu1.name
FROM
  score s1,
  student stu1
WHERE
  s1.StudentNo = stu1.StudentNo
GROUP BY s1.StudentNo
HAVING COUNT(*) < 
(
SELECT
  COUNT(*)
FROM
  course c1
)

(11)查询至少有一门课与学号为“001”的同学所学相同的同学的学号和姓名

SELECT DISTINCT
  stu1.StudentNo,
  stu1.name
FROM
  score s1,
  student stu1
WHERE
  s1.StudentNo = stu1.StudentNo
  AND
  s1.CourseNo IN
  (
  SELECT
    s2.CourseNo
  FROM
    score s2
  WHERE
    s2.StudentNo = 1
  )

(12)查询至少学过学号为“001”同学所有一门课的其他同学学号和姓名(和11题撞脸,排除1号同学就可以了)

SELECT DISTINCT
  stu1.StudentNo,
  stu1.name
FROM
  score s1,
  student stu1
WHERE
  s1.StudentNo = stu1.StudentNo
  AND
  s1.StudentNo != 1
  AND
  s1.CourseNo IN
  (
  SELECT
    s2.CourseNo
  FROM
    score s2
  WHERE
    s2.StudentNo = 1
  )

(13)把“score”表中“叶平”老师教的课的成绩都更改为此课程的平均成绩

-- 涉及将两表联合,将本表某字段的值按条件设置为另个表的某个字段的值 (参考链接:MySQL:把一个表中的数据按键值更新(update)到另一个表)
UPDATE
  score s,
  (
  SELECT
    s1.CourseNo as courseNo,
    AVG(s1.score) as avgScore 
  FROM
    score s1,
    course c1,
    teacher t1
  WHERE
    s1.CourseNo = c1.CourseNo
    AND
    c1.teacherNo = t1.teacherNo
    AND
    t1.name = '叶平'
  GROUP BY s1.CourseNo
  ) as t
SET
  s.score = t.avgScore
WHERE
  s.CourseNo = t.courseNo

(14)查询和“002”号的同学学习的课程完全相同的其他同学学号和姓名

SELECT
  stu.studentNo,
  stu.name
FROM
  score s,
  student stu
WHERE
  s.StudentNo != 2
  AND
  s.StudentNo = stu.studentNo
GROUP BY s.StudentNo
HAVING SUM(s.CourseNo)=
(
SELECT
  SUM(s1.CourseNo)
FROM
  score s1
WHERE
  s1.StudentNo = 2
)

(15)删除学习“叶平”老师课的SC表记录

DELETE FROM
  score s
WHERE
  s.CourseNo IN
  (
  SELECT
    c.CourseNo
  FROM
    course c,
    teacher t
  WHERE
    c.teacherNo = t.teacherNo
    AND
    t.name = '叶平'
  )

(16)向SC表中插入一些记录,这些记录要求符合以下条件:1、没有上过编号“002”课程的同学学号;2、插入“002”号课程的平均成绩

-- 本题采用插入子查询的方式,三个字段中后两个字段为常量(基本格式:INSERT INTO R(A1, A2 ... ,An) 子查询)
INSERT INTO
  score(StudentNo, CourseNo, score)
(
SELECT 
  stu.studentNo,
  2,
  (SELECT AVG(s3.score) FROM score s3 WHERE s3.CourseNo = 2)
FROM 
  student stu 
WHERE 
  stu.studentNo 
NOT IN 
(
SELECT 
  s2.StudentNo 
FROM 
  score s2 
WHERE 
  s2.CourseNo = 2
)
)

(17)按学号由低到高显示所有学生的“语文”、“数学”、“英语”三门的课程成绩,按如下形式显示: 学生ID,语文,数学,英语,有效课程数,有效平均分

-- 用了个极蠢的办法,虽然很瓜很绕但是也算是温习了下相关子查询、CASE WHEN、EXISTS了,另外对自己也有所启发,就留下了
-- 然后做到这里的时候感慨,随着练习总是越来越熟练的,尽管自己写得很绕,但以往是根本想不到用什么CASE WHEN、EXISTS之类的,也算是成长吧
SELECT
  stu.studentNo,
  CASE WHEN EXISTS (SELECT * FROM score s1 WHERE s1.CourseNo = 1 AND s1.studentNo = stu.studentNo) THEN (SELECT s.score FROM score s WHERE s.CourseNo = 1 AND s.studentNo = stu.studentNo) ELSE NULL END AS "语文",
  CASE WHEN EXISTS (SELECT * FROM score s2 WHERE s2.CourseNo = 2 AND s2.studentNo = stu.studentNo) THEN (SELECT s.score FROM score s WHERE s.CourseNo = 2 AND s.studentNo = stu.studentNo) ELSE NULL END AS "数学",
  CASE WHEN EXISTS (SELECT * FROM score s3 WHERE s3.CourseNo = 3 AND s3.studentNo = stu.studentNo) THEN (SELECT s.score FROM score s WHERE s.CourseNo = 3 AND s.studentNo = stu.studentNo) ELSE NULL END AS "英语",
  t1.validateCount AS '有效科目数',
  t2.validateAVG AS '有效平均分'
FROM
  student stu,
  (SELECT s.studentNo, COUNT(*) AS validateCount FROM score s WHERE s.CourseNo IN (1, 2, 3) GROUP BY s.StudentNo) as t1,
  (SELECT s.studentNo, AVG(s.score) AS validateAVG FROM score s WHERE s.CourseNo IN (1, 2, 3) GROUP BY s.StudentNo) as t2
WHERE
  stu.studentNo = t1.studentNo
  AND
  stu.studentNo = t2.studentNo
ORDER BY stu.StudentNo

-- 另外,参考博客中博主给出的答案如下,比我的就简洁多了,
-- 其次,他在这里的有效课程数和有效平均分是针对学生所有的成绩,而并非此处的仅仅三科
-- 因为题意也不是很清楚,也就作罢,正好算是两种形式吧
SELECT
  s.StudentNo,
  (SELECT s1.score FROM score s1 WHERE s1.CourseNo=1 AND s1.StudentNo = s.StudentNo) AS "语文",
  (SELECT s2.score FROM score s2 WHERE s2.CourseNo=2 AND s2.StudentNo = s.StudentNo) AS "数学",
  (SELECT s3.score FROM score s3 WHERE s3.CourseNo=3 AND s3.StudentNo = s.StudentNo) AS "英语",
  COUNT(s.CourseNo) AS "有效课程数",
  AVG(s.score) AS "有效平均分"
FROM
  score s
GROUP BY s.StudentNo
ORDER BY s.StudentNo

(18)查询各科成绩最高和最低的分:以如下形式显示:课程ID,最高分,最低分;

SELECT
  s.CourseNo,
  MAX(s.score),
  MIN(s.score)
FROM
  score s
GROUP BY
  s.CourseNo

(19)按各科平均成绩从低到高和及格率的百分数从高到低顺序;

-- 看了下上次在Github上写的,不得不说,practice makes perfect
SELECT
  s.CourseNo,
  c.name,
  AVG(s.score) AS '平均分',
  SUM(CASE WHEN s.score > 60 THEN 1 ELSE 0 END) AS '及格数',
  COUNT(*) AS '总数',
  SUM(CASE WHEN s.score > 60 THEN 1 ELSE 0 END)/COUNT(*)*100 AS '及格率'
FROM
  score s,
  course c
WHERE
  s.CourseNo = c.courseNo
GROUP BY s.CourseNo
ORDER BY AVG(s.score), SUM(CASE WHEN s.score > 60 THEN 1 ELSE 0 END)/COUNT(*) DESC

还不完全,参考原博主,加isnull

(20)查询不同老师所教不同课程平均分从高到低显示

SELECT
  c1.name,
  t1.name,
  AVG(s1.score)
FROM
  score s1,
  course c1,
  teacher t1
WHERE
  s1.CourseNo = c1.courseNo
  AND
  c1.teacherNo = t1.teacherNo
GROUP BY s1.CourseNo
ORDER BY AVG(s1.score) DESC

(21)统计列印各科成绩,各分数段人数:课程ID,课程名称,(100-85),(85-70,(70-60),( 低于60)

SELECT
  c.courseNo AS '课程ID',
  c.name AS '课程名称',
  SUM(CASE WHEN s.score BETWEEN 85 AND 100 THEN 1 ELSE 0 END) AS '(100-85)',
  SUM(CASE WHEN s.score BETWEEN 70 AND 85 THEN 1 ELSE 0 END) AS '(85-70)',
  SUM(CASE WHEN s.score BETWEEN 60 AND 70 THEN 1 ELSE 0 END) AS '(70-60)',
  SUM(CASE WHEN s.score < 60 THEN 1 ELSE 0 END) AS '(低于60)'
FROM
  course c,
  score s
WHERE
  c.courseNo = s.CourseNo
GROUP BY c.courseNo

(22)查询各科成绩前三名的记录(不考虑成绩并列情况)

SELECT
	*
FROM
  score s
WHERE
  (
	SELECT
		COUNT(*)
	FROM
		score s1
	WHERE
		s1.CourseNo = s.CourseNo
		AND
		s1.score > s.score
	) < 3
ORDER BY s.CourseNo

(23)查询每门课程被选修的学生数

SELECT
  c.name AS '课程',
  COUNT(s.StudentNo) AS '选修学生数'
FROM
  course c LEFT JOIN score s ON c.courseNo = s.CourseNo
GROUP BY c.courseNo

(24)查询出只选修了一门课程的全部学生的学号和姓名

SELECT
  stu1.StudentNo AS '学号',
	stu1.name AS '姓名'
FROM
  (SELECT StudentNo, COUNT(CourseNo) AS amount FROM score GROUP BY StudentNo) t1,
  student stu1
WHERE
  t1.StudentNo = stu1.studentNo
  AND
  t1.amount = 1

SELECT
  stu1.studentNo AS '学号',
  stu1.name AS '姓名'
FROM
  score s,
  student stu1
WHERE
  s.StudentNo = stu1.studentNo
GROUP BY s.StudentNo
HAVING COUNT(s.CourseNo) = 1

(25)查询男生、女生的人数

SELECT
  s.sex AS '性别',
  COUNT(*) AS '人数'
FROM
  student s
GROUP BY s.sex

(26)查询同名同姓学生名单,并统计同名人数

SELECT
  s.name AS '姓名',
  COUNT(*) AS '学生数'
FROM
  student s
GROUP BY s.name

(27)查询1991年出生的学生名单

SELECT
  s.name AS '姓名'
FROM
  student s
WHERE
  YEAR(CURDATE()) - s.age = 1991

(28)查询每门课程的平均成绩,结果按平均成绩升序排列

#未考虑到课程无人选修的情况
SELECT
  c.name AS '课程名称',
  AVG(s.score) AS '平均成绩'
FROM
  score s,
  course c
WHERE
  s.CourseNo = c.courseNo
GROUP BY c.courseNo
ORDER BY AVG(s.score)



#如果某课程无人选修,其平均成绩显示为null
SELECT
  c.name AS '课程名称',
  AVG(s.score) AS '平均成绩'
FROM
  course c LEFT JOIN score s ON c.courseNo = s.CourseNo
GROUP BY c.courseNo  
ORDER BY AVG(s.score)

(29)查询平均成绩大于85的所有学生的学号、姓名和平均成绩

SELECT
  stu.studentNo AS '学号',
  stu.name AS '姓名',
  AVG(s.score) AS '平均成绩'
FROM
  score s,
  student stu
WHERE
  s.StudentNo = stu.studentNo
GROUP BY s.StudentNo
HAVING AVG(s.score) > 85

(30)查询课程名称为“数学”,且分数低于60的学生姓名和分数

SELECT
  stu.name AS '姓名',
  s.score AS '数学成绩'
FROM
  score s,
  course c,
  student stu
WHERE
  s.CourseNo = c.courseNo
  AND
  s.StudentNo = stu.studentNo
  AND
  c.name = '数学'
  AND
  s.score < 60

(31)查询所有学生的选课情况

SELECT
  stu.name AS '姓名',
  c.name AS '选课'
FROM
  score s,
  course c,
  student stu
WHERE
  s.CourseNo = c.courseNo
  AND
  s.StudentNo = stu.studentNo
ORDER BY stu.name

(32)查询任何一门课程成绩在70分以上的姓名、课程名称和分数

SELECT
  stu.name AS '姓名',
  c.name AS '课程名称',
  s.score AS '分数'
FROM
  score s,
  student stu,
  course c
WHERE
  s.StudentNo = stu.studentNo
  AND
  s.CourseNo = c.courseNo
  AND
  s.score > 70

(33)查询不及格的课程,并按课程号从大到小排列

#包含不及格记录的课程
SELECT DISTINCT
  c.courseNo AS '课程号',
  c.name AS '课程名称' 
FROM
  score s,
  course c
WHERE
  s.CourseNo = c.courseNo
  AND
  s.score < 60

#不及格的课程的选修记录
SELECT
  stu.name AS '姓名',
  c.name AS '课程名称',
  s.score AS '分数'
FROM
  score s,
  student stu,
  course c
WHERE
  s.StudentNo = stu.studentNo
  AND
  s.CourseNo = c.courseNo
  AND
  s.score < 60
ORDER BY c.courseNo DESC

(34)查询课程编号为003且课程成绩在80分以上的学生的学号和姓名

SELECT
  stu.studentNo AS '学号',
  stu.name AS '姓名'
FROM
  score s,
  student stu
WHERE
  s.StudentNo = stu.studentNo
  AND
  s.CourseNo = 3
  AND
  s.score > 80

(35)求选了课程的学生人数

#method-1
SELECT
  COUNT(DISTINCT s.StudentNo) AS '选了课程的学生人数'
FROM
  score s

#method-2
SELECT
  COUNT(*) AS '选了课程的学生人数'
FROM
  (SELECT * FROM score s GROUP BY s.StudentNo) t

(36)查询选修“杨艳”老师所授课程的学生中,成绩最高的学生姓名及其成绩

SELECT
  stu.name AS '学生姓名',
  s.score AS '成绩'
FROM
  score s,
  student stu,
  course c,
  teacher t
WHERE
  s.StudentNo = stu.studentNo
  AND
  s.CourseNo = c.courseNo
  AND
  c.teacherNo = t.teacherNo
  AND
  t.name = '杨艳'
ORDER BY s.score DESC
LIMIT 0, 1

(37)查询各个课程及相应的选修人数

SELECT
  c.name AS '课程名称',
  COUNT(*) AS '选修人数'
FROM
  score s,
  course c
WHERE
  s.CourseNo = c.courseNo
GROUP BY s.CourseNo

(38)查询不同课程但成绩相同的学生的学号、课程号、学生成绩

#method-1
SELECT
  s.StudentNo AS '学号',
  s.CourseNo AS '课程号',
  s.score AS '成绩'
FROM
  score s
WHERE
  (SELECT COUNT(*) FROM score s1 WHERE s1.score = s.score AND s1.CourseNo <> s.COurseNo) > 0
ORDER BY s.score DESC, s.StudentNo, s.CourseNo

#method-2
SELECT DISTINCT
  s1.StudentNo AS '学号',
  s1.CourseNo AS '课程号',
  s1.score AS '成绩'
FROM
  score s1,
  score s2
WHERE
  s1.score = s2.score 
  AND
  s1.CourseNo <> s2.CourseNo
  ORDER BY s1.score DESC, s1.StudentNo, s1.CourseNo

(39)查询每门课程成绩最好的前两名

SELECT
  s.CourseNo AS '课程号',
  s.StudentNo AS '学号',
  s.score AS '分数'
FROM
  score s
WHERE
  (SELECT COUNT(*) FROM score s1 WHERE s1.CourseNo = s.CourseNo AND s1.score > s.score) < 2
ORDER BY s.CourseNo














持续更新:
2017-06-28

附件列表

    原文地址:https://www.cnblogs.com/deng-cc/p/6515166.html