数据库例题 - 期末

数据库及表的创建

用SQL创建符合如下条件的数据库:数据库名为:StudentsDB

选用已建立的“StudentsDB”,写出创建满足表C-1到C-3条件的表的SQL语句,并执行所写代码

表C-1 Student表结构

列名 说明 数据类型 约束
Sno 学号 普通编码定长字符串,长度为7 主键
Sname 姓名 普通编码定长字符串,长度为10 非空
Ssex 性别 普通编码定长字符串,长度为2 取值范围:
Sage 年龄 微整型(tinyint) 取值范围:15 - 45
Sdept 所在系 普通编码不定长字符串,长度为20 默认值为“计算机系”
Sid 身份证号 普通编码定长字符串,长度为 取值不重
Sdate 入学日期 小日期时间 默认为系统当前日期
CREATE TABLE Student (
	Sno		CHAR(7)		PRIMARY KEY,
    Sname	CHAR(10)	NOT NULL,
    Ssex	CHAR(2)		CHECK (Ssex IN ('男','女')),
    Sage	TINYINT		CHECK (Sage BETWEEN 15 AND 45),
    Sdept	VARCHAR(20)	DEFAULT '计算机系',
    Sid		CHAR(10)	UNIQUE,
    Sdate	SMALLDATETIME	DEFAULT GETDATE()
);

表C-2 Course表结构

列名 说明 数据类型 约束
Cno 课程号 普通编码定长字符串,长度为10 主键
Cname 课程名 普通编码不定长字符串,长度为20 非空
Credit 学时数 整型 取值大于0
Semester 学分 小整型
CREATE TABLE Course (
	Cno			CHAR(10)		PRIMARY KEY,
    Cname		VARCHAR(20)		NOT NULL,
    Credit		INT				CHECK (Credit > 0)
    Semester	SMALLINT
);

表C-3 SC表结构

列名 说明 数据类型 约束
Sno 学号 普通编码定长字符串,长度为7 主键,引用Student的外键
Cno 课程号 普通编码定长字符串,长度为10 主键,引用Course的外键
Grade 成绩 小整型 取值范围为0-100
CREATE TABLE SC (
    Sno		CHAR(7),
    Cno		CHAR(10),
    Grade	SMALLINT CHECK (Grade BETWEEN 0 AND 100),
    PRIMARY KEY (Sno, Cno),
    FOREIGN KEY (Sno) REFERENCES Student(Sno),
    FOREIGN KEY (Cno) REFERENCES Course(Cno)
);

单表查询

查询缺考的学生的学号和课程号

SELECT Sno, Cno
FROM SC
WHERE Grade IS NULL;

查询年龄为空值的学生的学号和姓名

SELECT Sno, Sname
FROM Student
WHERE Sage IS NULL;

查询计算机系 20 岁以下的学生学号和姓名

WHERE Sdept = '计算机系' AND Sage < 20;

查询计算机系、数学系、信息系的学生姓名、性别

SELECT Sname, Ssex
FROM Student
WHERE Sdept IN ('计算机系', '数学系', '信息系');

查询选修 C001 课程的学生的学号和成绩,按分数降序

SELECT Sno, Grade
FROM SC
WHERE Cno = 'C001'
ORDER BY Grade DESC;

查询选修 C001 课程的所有学生的总成绩

SELECT SUM(Grade) AS TotalGrade
FROM SC
WHERE Cno = 'C001';

查询 C001 课程的最高分和最低分

SELECT 
    MAX(Grade) AS MaxGrade,
    MIN(Grade) AS MinGrade
FROM SC
WHERE Cno = 'C001';

查询全体学生,按系升序,同系按年龄降序

SELECT *
FROM Student
ORDER BY Sdept ASC, Sage DESC;

查询学生总人数

SELECT COUNT(*) AS StudentCount
FROM Student;

查询计算机系的男学生总人数

SELECT COUNT(*) AS MaleCSCount
FROM Student
WHERE Sdept = '计算机系' AND Ssex = '男';

查询选修了课程的学生人数(去重)

SELECT COUNT(DISTINCT Sno) AS StudentWithCourse
FROM SC;

计算选修 C001 课程的学生平均成绩

SELECT AVG(Grade) AS AvgGrade
FROM SC
WHERE Cno = 'C001'

查询各课程及选课人数

SELECT Cno, COUNT(*) AS StudentCount
FROM SC
GROUP BY Cno;

多表查询

(1)查询每个选修了课程的学生学号、姓名、所在系及其选修课程编号。

SELECT s.Sno, s.Sname, s.Sdept, sc.Cno
FROM Student s
INNER JOIN SC sc ON s.Sno = sc.Sno;

(2)查询选修了C002课程且成绩在60分以上的所有学生的学号和姓名。

SELECT s.Sno, s.Sname
FROM Student s
INNER JOIN SC sc ON s.Sno = sc.Sno
WHERE sc.Cno = 'C002' AND sc.Grade > 60;

(3)查询每个学生选修的课程名及其成绩

SELECT s.Sname, c.Cname, sc.Grade
FROM Student s
INNER JOIN SC sc ON s.Sno = sc.Sno
INNER JOIN Course c ON sc.Cno = c.Cno;

(4)查询“计算机系”每个学生的学号、姓名、选修课程的课程名及成绩

SELECT s.Sno, s.Sname, c.Cname, sc.Grade
FROM Student s
LEFT JOIN SC sc ON s.Sno = sc.Sno
LEFT JOIN Course c ON sc.Cno = c.Cno
WHERE s.Sdept = '计算机系';

(5)统计每一年龄选修课程的学生人数。

SELECT s.Sage, COUNT(DISTINCT s.Sno) AS StudentCount
FROM Student s
INNER JOIN SC sc ON s.Sno = sc.Sno
GROUP BY s.Sage;

(6)查询选了C002课程的学生姓名和所在系。

SELECT s.Sname, s.Sdept
FROM Student s
INNER JOIN SC sc ON s.Sno = sc.Sno
WHERE sc.Cno = 'C002';

(7)查询考试成绩80分以上的学生姓名、课程号和成绩,并按成绩降序排列结果。

SELECT s.Sname, sc.Cno, sc.Grade
FROM Student s
INNER JOIN SC sc ON s.Sno = sc.Sno
WHERE sc.Grade > 80
ORDER BY sc.Grade DESC;

(8)查询与“数据结构”在同一学期开设的课程的课程名和开课学期。

SELECT Cname, Semester
FROM Course
WHERE Semester = (
    SELECT Semester
    FROM Course 
    WHERE Cname = '数据结构')
  AND Cname != '数据结构';

(9)查询与李勇年龄相同的学生的姓名、所在系和年龄。

SELECT Sname, Sdept, Sage
FROM Student
WHERE Sage = (SELECT Sage FROM Student WHERE Sname = '李勇')
  AND Sname != '李勇';

(10)查询哪些课程没有学生选修,列出课程号和课程名。

SELECT c.Cno, c.Cname
FROM Course c
LEFT JOIN SC sc ON c.Cno = sc.Cno
WHERE sc.Cno IS NULL;

(11)查询每个学生的选课情况,包括未选课的学生,列出学生的学号、姓名、选的课程号。

SELECT s.Sno, s.Sname, sc.Cno
FROM Student s
LEFT JOIN SC sc ON s.Sno = sc.Sno;

(12)查询计算机系哪些学生没有选课,列出学生姓名。

SELECT s.Sname
FROM Student s
LEFT JOIN SC sc ON s.Sno = sc.Sno
WHERE s.Sdept = '计算机系' AND sc.Sno IS NULL;

嵌套查询

(1)查询选修了"C001"课程的学生姓名。

SELECT DISTINCT s.Sname
FROM Student s
INNER JOIN SC sc ON s.Sno = sc.Sno
WHERE sc.Cno = 'C001';

(2)查询与"李勇"在同一个系学习的学生姓名,系别和性别。

SELECT Sname, Sdept, Ssex
FROM Student
WHERE Sdept = (SELECT Sdept FROM Student WHERE Sname = '李勇')
  AND Sname != '李勇';

(3)查询选修课程名为"高等数学"的学生学号和姓名。

SELECT s.Sno, s.Sname
FROM Student s
INNER JOIN SC sc ON s.Sno = sc.Sno
INNER JOIN Course c ON sc.Cno = c.Cno
WHERE c.Cname = '高等数学';

(4)与第2题相同,查询与"李勇"在同一个系学习的学生姓名,系别和性别。

(5)与第3题相同,查询选修课程名为"高等数学"的学生学号和姓名。

(6)查询计算机系成绩80分以上的学生的学号和姓名。

SELECT s.Sno, S.Sname
FROM Student s
JOIN SC sc on s.Sno = sc.Sno
WHERE s.Sdept = '计算机系' AND sc.Grade > 80;

(7)查询计算机系考试成绩最高的学生的姓名。

-- 方法1:使用子查询
SELECT TOP 1 s.Sname
FROM Student s
INNER JOIN SC sc ON s.Sno = sc.Sno
WHERE s.Sdept = '计算机系'
ORDER BY sc.Grade DESC;

-- 方法2:使用MAX函数
SELECT s.Sname
FROM Student s
INNER JOIN SC sc ON s.Sno = sc.Sno
WHERE s.Sdept = '计算机系' 
  AND sc.Grade = (
    SELECT MAX(Grade) 
    FROM SC 
    WHERE Sno IN (SELECT Sno FROM Student WHERE Sdept = '计算机系')
  );

(8)查询年龄最大的男学生的姓名和年龄。

-- 方法1
SELECT TOP 1 Sname, Sage
FROM Student
WHERE Ssex = '男'
ORDER BY Sage DESC;

-- 方法2
SELECT Sname, Sage
FROM Student
WHERE Ssex = '男' 
  AND Sage = (SELECT MAX(Sage) FROM Student WHERE Ssex = '男');

(9)查询C001课程的考试成绩高于该课程平均成绩的学生的学号和成绩。

SELECT sc.Sno, sc.Grade
FROM SC sc
WHERE sc.Cno = 'C001' 
  AND sc.Grade > (SELECT AVG(Grade) FROM SC WHERE Cno = 'C001')
ORDER BY sc.Grade DESC;

(10)查询计算机系学生考试成绩高于计算机系学生平均成绩的学生的姓名、考试的课程名和考试成绩。

SELECT s.Sname, c.Cname, sc.Grade
FROM Student s
INNER JOIN SC sc ON s.Sno = sc.Sno
INNER JOIN Course c ON sc.Cno = c.Cno
WHERE s.Sdept = '计算机系'
  AND sc.Grade > (
    SELECT AVG(sc2.Grade)
    FROM Student s2
    INNER JOIN SC sc2 ON s2.Sno = sc2.Sno
    WHERE s2.Sdept = '计算机系'
  )
ORDER BY sc.Grade DESC;

(11)查询"高等数学"课程考试成绩高于"高等数学"平均成绩的学生姓名和"高等数学"成绩。

SELECT s.Sname, sc.Grade
FROM Student s
INNER JOIN SC sc ON s.Sno = sc.Sno
INNER JOIN Course c ON sc.Cno = c.Cno
WHERE c.Cname = '高等数学'
  AND sc.Grade > (
    SELECT AVG(sc2.Grade)
    FROM SC sc2
    INNER JOIN Course c2 ON sc2.Cno = c2.Cno
    WHERE c2.Cname = '高等数学'
  )
ORDER BY sc.Grade DESC;

(12)查询没选"高等数学"的学生姓名和所在系。

-- 方法1:使用NOT EXISTS
SELECT s.Sname, s.Sdept
FROM Student s
WHERE NOT EXISTS (
    SELECT 1
    FROM SC sc
    INNER JOIN Course c ON sc.Cno = c.Cno
    WHERE sc.Sno = s.Sno AND c.Cname = '高等数学'
);

-- 方法2:使用NOT IN
SELECT Sname, Sdept
FROM Student
WHERE Sno NOT IN (
    SELECT sc.Sno
    FROM SC sc
    INNER JOIN Course c ON sc.Cno = c.Cno
    WHERE c.Cname = '高等数学'
);

规范化理论

查询至少选修了1门课程的学生的姓名(用相关子查询实现)

SELECT Sname
FROM Student
WHERE Sno IN (
	SELECT DISTINCT sc.Sno
	FROM Sc sc
)

查询没有选修任何课程的学生的学号和姓名

SELECT Sno,Sname
FROM Student
WHERE Sno NOT IN (
	SELECT DISTINCT Sno
    FROM SC
);

查询选修了"数据库原理"课程的学生的平均成绩

SELECT AVG(sc.Grade) AS 数据库原理平均分
FROM SC sc
INNER JOIN Course c ON sc.Cno = c.Cno
WHERE c.Cname = '数据库原理';

查询平均成绩高于全体学生总平均成绩的学生学号和平均分,并按平均分降序排列

SELECT s.Sno, AVG(sc.Grade) AS 平均分
FROM Student s
INNER JOIN SC sc ON sc.Sno = s.Sno
GROUP BY s.Sno
HAVING AVG(sc.Grade) > (
	SELECT AVG(Grade)
	FROM SC 
)
ORDER BY AVG(sc.Grade) DESC

查询每个学生取得最高分的那门课程的成绩信息,显示学号、课程号、成绩

SELECT sc1.Sno, sc1.Cno, sc1.Grade
FROM SC sc1
WHERE sc1.Grade = (
	SELECT MAX(sc2.Grade)
	FROM SC sc2
	WHERE sc1.Sno = sc2.Sno
);