问答题 现有关系数据库如下:
学生(学号,姓名,性别,年龄,籍贯,专业)
课程(课程号,课程名,学分)
选课(学号,课程号,成绩)
用SQL语言实现以下操作:

问答题 查询籍贯为湖南的男生的姓名和年龄。
【正确答案】当有多个条件表达式需要同时满足时,条件表达式之间用AND连接。
SELECT姓名,年龄
FROM学生
WHERE籍贯='湖南' AND 性别='男'
【答案解析】
问答题 查询年龄在20~22岁之间的学生的全部信息,并按年龄降序排列。
【正确答案】在SQL语言中,使用ORDER BY子句可以对查询结果进行排序,如果是升序则使用关键字ASC,如果是降序则使用DESC。
SELECT *
FROM 学生
WHERE 年龄 BETWEEN 20 AND 22
ORDER BY 年龄 DESC
【答案解析】
问答题 查询年龄小于23岁,籍贯是湖南、湖北、广东或广西的学生的学号和姓名。
【正确答案】在确定的集合中可以使用IN关键字来查找属性值,当列中的值与IN中某个常量值相等时,则结果为true,表明此记录为符合查询条件的记录。
SELECT 学号,姓名
FROM 学生
WHERE 年龄<23 AND 籍贯 IN('湖南','湖北','广东','广西')
【答案解析】
问答题 查询学生表中籍贯为空值的学生的学号和姓名。
【正确答案】使用IS NULL来判断某个值是否为空值,空值表示不确定的值。
SELECT 学号,姓名
FROM 学生
WHERE 籍贯 IS NULL
【答案解析】
问答题 查询学生表中姓刘的湖南学生的学号和姓名。
【正确答案】可以使用LIKE关键字来进行字符串匹配,下画线()表示匹配任意一个字符,百分号(%)表示匹配0个或多个字符。
SELECT 学号,姓名
FROM 学生
WHERE 籍贯='湖南' AND 姓名 LIKE '刘%'
【答案解析】
问答题 查询学生张三选修的不及格(成绩小于60分且不为空)课程门数。
【正确答案】由于学生成绩和学生姓名位于不同的表中,因此需要将学生表和选课表进行连接,可以采用INNER JOIN关键字来连接两张表,使用聚合函数COUNT()来统计元组个数。
SELECT COUNT(*)
FROM 学生 INNER JOIN 选课 ON 学生.学号=选课.学号
WHERE 姓名='张三' AND 成绩<60 AND 成绩 IS NOT NULL
【答案解析】
问答题 查询学生的最小年龄、最大年龄和平均年龄。
【正确答案】可以使用聚合函数MIX()来求列值的最小值、MAX()来求列值的最大值、AVG()来求列值的平均值。
SELECT MIN(年龄),MAX(年龄),AVG(年龄)
FROM 学生
【答案解析】
问答题 查询年龄超过平均年龄的学生姓名。
【正确答案】可以先使用子查询得到学生的平均年龄,然后通过比较得到符合条件的学生姓名。
SELECT 姓名
FROM 学生
WHERE 年龄>
(SELECT AVG(年龄)
FROM学生)
【答案解析】
问答题 查询各门课程的课程号和平均成绩,要求该课程选修学生人数至少超过3人。
【正确答案】首先需要按照课程号对选课表进行分组,然后对各组记录计算AVG(成绩),最后使用HAVING子句来对查询结果进行筛选。
SELECT 课程号,AVG (成绩) AS平均分
FROM选课
GROUP BY课程号
HAVING COUNT (学号)>=3
【答案解析】
问答题 查询没有选修任何课程的学生的学号和姓名。
【正确答案】可以通过嵌套子查询结合NOT EXISTS来实现该查询,外查询每一行运行一次子查询,根据返回值测试NOT EXISTS来生成结果表中的一行。子查询可以使用外查询中的列,不过如果出现属性歧义则必须带有表名前缀,否则将被视为子查询中所指定的源表中的列。
SELECT学号,姓名
FROM学生
WHERE NOT EXISTS
(SELECT *
FROM选课
WHERE 学生.学号=选课.学号)
【答案解析】
问答题 查询选修了课程名为“数据库原理”的所有学生的姓名。
【正确答案】本查询涉及3个表,可以使用连接条件“学生.学号=选课.学号”和“选课.课程号=课程.课程号”将3个表连接起来。
SELECT 姓名
FROM 学生,选课,课程
WHERE 学生.学号=选课.学号 AND 选课.课程号=课程.课程号 AND 课程名='数据库原理'
【答案解析】
问答题 查询至少选修了两门课程的学生的学号。
【正确答案】可以使用自连接的方式来实现本查询。在自连接中需要给表取别名,以使它们作为不同的表使用。将课程表取别名为C1和C2,当C1和C2按学号连接后,再从中筛选出C1.课程号不等于C2.课程号的元组。其学号对应的是两门不同的课程号,若一个学生同时选修了两门或两门以上的课程,则必然会选出该学生号的重复元组,因此在SELECT子句中需要使用DISTINCT关键字对重复元组进行合并。
SELECT DISTINCT C1.学号
FROM 选课AS C1,选课AS C2
WHERE C1.学号=C2.学号 AND C1.课程号<>C2.课程号
【答案解析】
问答题 查询所有学生的选课情况,并且同时显示没有选修任何课程的学生信息。
【正确答案】要求显示学生的全部选课信息和没有选修任何课程的学生信息,即学生表需要全部显示,可以使用左外连接“LEFT[OUTER]JOIN”来实现。
SELECT *
FROM 学生 LEFT JOIN 选课 ON 学生.学号=选课.学号
【答案解析】
问答题 查询至少选修一门课程的所有学生信息。
【正确答案】可以通过嵌套子查询来实现本功能。将学生表作为外查询的源表,选课表作为内查询的源表,对于学生表中的每一条记录,都使用它的学号去查询选课表中的学号列。如果选课表中至少有一个值与该学号相等,即子查询结果非空,外查询条件为真,外查询就把学生记录查询出来。
SELECT *
FROM 学生
WHERE EXISTS
(SELECT *
FROM 选课
WHERE 选课.学号=学生.学号)
【答案解析】
问答题 查询选修了课程表中所有课程的学生信息。
【正确答案】本查询较为复杂,可以设计一个三重嵌套查询来实现。对于三重循环,最外层循环依次扫描学生表中的每个元组,中层循环依次扫描课程表中的每个元组,内层循环依次扫描选课表中的每个元组。对于学生表中的每个元组,若有一门课程没有选修的话,则最内层的查询就为空,进而得出中层的选择条件为真,再得出中层的查询不为空,接着得出外层的选择条件为假,最后得出该学生元组不会被选择出来;只有所有课程都被某个学生选修时,最内层循环的查询每次都不为空,进而得出中层的选择条件每次都为假,接着得出中层的查询结果为空,由此得到外层的选择条件为真,该学生记录就被选择出来。
SELECT *
FROM 学生
WHERE NOT EXISTS
(SELECT *
FROM 课程
WHERE NOT EXISTS
(SELECT *
FROM 选课
WHERE 学生.学号=选课.学号 AND 课程.课程号=选课.课程号
)
)
【答案解析】
问答题 查询出与学生“张三”至少有一门相同选修课程的所有学生信息。
【正确答案】对于学生表中的每一个元组,若它的姓名不等于“张三”,同时用它的学号到选课表中去查询对应的元组。若该元组的课程号等于张三所选的任一个课程号,则可用EXISTS来判断子查询是否为空;如果子查询非空,则外循环的选择条件为真,该学生记录就被选择出来。
SELECT *
FROM 学生 S1
WHERE S1.姓名<>'张三' AND EXISTS
(SELECT SC1.课程号
FROM 选课 SC1
WHERE SC1.学号=S1.学号 AND SC1.课程号=ANY
(SELECT SC2.课程号
FROM 学生 S2,选课 SC2
WHERE S2.学号=SC2.学号 AND S2.姓名='张三'
)
)
【答案解析】
问答题 查询每个学生的学号、姓名和所选课程的门数。
【正确答案】可以对选课表中的学号进行分组统计,但查询结果要求包括学号、姓名和所选课程门数3列。在选择列表中的列要么包含在聚合函数中,要么包含在GROUP BY子句中,否则会出错,因此在GROUP BY子句中应该包含学号和姓名两列。
SELECT SC.学号,S.姓名,COUNT(SC.学号)
FROM 学生 AS S,选课AS SC
WHERE S.学号=SC.学号
GROUP BY SC.学号,S.姓名
【答案解析】
问答题 查询选修课程门数超过一门的学生的信息。
【正确答案】选修课程门数超过一门的学生学号可以通过对选课表按学号进行分组统计得到,再使用IN关键字即可实现本查询功能。
SELECT *
FROM 学生
WHERE 学号 IN
(SELECT 学号
FROM 选课
GROUP BY 学号
HAVING COUNT(学号)>1)
【答案解析】
问答题 查询学生“张三”没有选修的课程的课程号。
【正确答案】可以使用嵌套子查询来实现,先查询出学生“张三”选修的全部课程的课程号,然后使用NOT IN关键字找出“张三”没有选修的课程的课程号。
SELECT 课程号
FROM 课程
WHERE 课程号 NOT IN
(SELECT 课程号
FROM 选课
WHERE 学号 IN
(SELECT 学号
FROM 学生
WHERE 姓名='张三'
)
)
【答案解析】
问答题 查询学生表中所有男生信息,并将查询结果保存在一个新表中,表名为男生信息。
【正确答案】可以使用INTO子句将查询结果保存在一个新表中。
SELECT *
INTO男生信息
FROM 学生
WHERE 性别='男'
【答案解析】