# 题目重述
根据提供的《数据库系统课程设计项目任务书.docx》内容,需完成一个基于 MySQL 的完整数据库项目作业,具体包括:
1. **数据库与表的设计与创建**:在 `teachingdb` 数据库中创建 `student`、`course`、`teach` 和 `score` 四张表,并设置主键、外键及约束。
2. **数据插入**:将指定数据插入四张表中。
3. **基础 SQL 操作**:执行字段增删改、数据增删改查、条件查询、聚合统计、连接查询、子查询等共计 31 项操作。
4. **高级数据库编程**:实现存储过程、函数、触发器共 5 项,用于模糊查询、学分统计、自动更新总学分、级联删除等功能。
---
# 详解
## 一、数据库与表的创建
```sql
-- 创建数据库
CREATE DATABASE IF NOT EXISTS teachingdb CHARACTER SET utf8mb4;
USE teachingdb;
-- 创建学生表 student
CREATE TABLE student (
sno CHAR(5) PRIMARY KEY,
sname VARCHAR(20) NOT NULL,
sdept VARCHAR(20) NOT NULL,
sclass CHAR(2) NOT NULL,
ssex CHAR(2),
sbirth DATE,
total_credit INT DEFAULT 0
);
-- 创建课程表 course
CREATE TABLE course (
cno CHAR(3) PRIMARY KEY,
cname VARCHAR(50) NOT NULL,
credit_hour INT,
credit DECIMAL(3,1)
);
-- 创建教师表 teach
CREATE TABLE teach (
tno CHAR(6) PRIMARY KEY,
tname VARCHAR(20) NOT NULL,
tsex CHAR(2),
tdept VARCHAR(20)
);
-- 创建成绩表 score
CREATE TABLE score (
sno CHAR(5),
cno CHAR(3),
tno CHAR(6),
grade DECIMAL(4,1),
PRIMARY KEY (sno, cno, tno),
FOREIGN KEY (sno) REFERENCES student(sno),
FOREIGN KEY (cno) REFERENCES course(cno),
FOREIGN KEY (tno) REFERENCES teach(tno)
);
```
---
## 二、数据插入
```sql
-- 插入学生数据
INSERT INTO student VALUES
('96001','马小燕','计算机','01','女','2000-01-02',0),
('96002','黎明','计算机','01','男','2000-03-05',0),
('96003','刘东明','数学','01','男','2000-10-05',0),
('96004','赵志勇','信息','02','男','2000-08-08',0),
('97001','马蓉','数学','02','女','2001-03-04',0),
('97002','李成功','计算机','01','男','2001-09-10',0),
('97003','黎明','信息','03','女','2002-02-08',0),
('97004','李丽','计算机','02','女','2002-01-05',0),
('96005','司马志明','计算机','02','男','2001-11-23',0);
-- 插入课程数据
INSERT INTO course VALUES
('001','数学分析',64,4),
('002','普通物理',64,4),
('003','微机原理',56,3.5),
('004','数据结构',64,4),
('005','操作系统',56,3.5),
('006','数据库原理',56,3.5),
('007','编译原理',48,3),
('008','程序设计',32,2);
-- 插入教师数据
INSERT INTO teach VALUES
('052501','王成刚','男','计算机'),
('052502','李正科','男','计算机'),
('052503','严敏','女','数学'),
('052504','赵高','男','数学'),
('052505','刘玉兰','女','计算机'),
('052506','王成刚','男','信息'),
('052507','马悦','女','计算机');
-- 插入成绩数据
INSERT INTO score VALUES
('96001','001','052503',77.5),('96001','003','052501',89),('96001','004','052502',86),
('96001','005','052505',82),('96002','001','052504',88),('96002','003','052502',92.5),
('96002','006','052507',90),('96005','004','052502',92),('96005','005','052505',90),
('96005','006','052505',89),('96005','007','052507',78),('96003','001','052504',69),
('97001','001','052504',96),('97001','008','052505',95),('96004','001','052503',87),
('96003','003','052501',91),('97002','003','052502',91),('97002','004','052505',NULL),
('97002','006','052507',92),('97004','005','052502',90),('97004','006','052501',85);
```
---
## 三、基础 SQL 功能实现
```sql
-- 1. 增加籍贯字段
ALTER TABLE student ADD nativeplace VARCHAR(20);
-- 2. 删除籍贯字段
ALTER TABLE student DROP COLUMN nativeplace;
-- 3. 修改 ssex 字段类型
ALTER TABLE student MODIFY ssex VARCHAR(3);
-- 4. 在 course.cname 上添加唯一约束
ALTER TABLE course ADD CONSTRAINT uk_cno UNIQUE(cname);
-- 5. 插入新学生
INSERT INTO student VALUES('11111','马明','计算机','01','女','2000-01-02',NULL);
-- 6. 所有学生总学分加 2(含 NULL)
UPDATE student SET total_credit = IFNULL(total_credit, 0) + 2;
-- 7. 修改马小燕出生日期
UPDATE student SET sbirth = '2000-01-22' WHERE sname = '马小燕';
-- 8. 删除学号为 '11111' 的学生
DELETE FROM student WHERE sno = '11111';
-- 9. 创建表 s1,结构内容相同
CREATE TABLE s1 AS SELECT * FROM student;
-- 10. 删除 s1 中计算机系学生
DELETE FROM s1 WHERE sdept = '计算机';
-- 11. 删除 s1 表
DROP TABLE s1;
-- 12. 2000 年出生的学生(中文列名)
SELECT sno AS 学号, sname AS 姓名 FROM student WHERE YEAR(sbirth) = 2000;
-- 13. 选修课程的学生学号(去重)
SELECT DISTINCT sno FROM score;
-- 14. 学时在 1-50 之间的课程
SELECT * FROM course WHERE credit_hour BETWEEN 1 AND 50;
-- 15. 不是计算机系或信息系的学生
SELECT * FROM student WHERE sdept NOT IN ('计算机', '信息');
-- 16. 姓名至少三字且倒数第三字为“马”
SELECT sname FROM student WHERE CHAR_LENGTH(sname) >= 3 AND SUBSTR(sname, -3, 1) = '马';
-- 17. 选修 052501 教师,成绩 80~90,学号 96xxx
SELECT * FROM score WHERE tno = '052501' AND grade BETWEEN 80 AND 90 AND sno LIKE '96%';
-- 18. 没有成绩的学生(成绩为 NULL)
SELECT sno, cno FROM score WHERE grade IS NULL;
-- 19. 学生总人数
SELECT COUNT(*) AS 学生总数 FROM student;
-- 20. 选修课程的学生人数
SELECT COUNT(DISTINCT sno) AS 选修人数 FROM score;
-- 21. 各门课程的最高、最低、平均成绩
SELECT cno, MAX(grade), MIN(grade), AVG(grade) FROM score GROUP BY cno;
-- 22. 学生人数不足 3 人的系
SELECT sdept, COUNT(*) AS cnt FROM student GROUP BY sdept HAVING cnt < 3;
-- 23. 计算机系各班人数,倒序排列
SELECT sclass, COUNT(*) AS cnt FROM student WHERE sdept = '计算机' GROUP BY sclass ORDER BY cnt DESC;
-- 24. 自然连接:选修严敏老师“数学分析”课程的学生
SELECT s.sname, c.cname, t.tname, sc.grade
FROM student s, course c, teach t, score sc
WHERE s.sno = sc.sno AND c.cno = sc.cno AND t.tno = sc.tno
AND t.tname = '严敏' AND c.cname = '数学分析';
-- 25. 等值连接:选修“数学分析”的学生姓名、课程名、成绩
SELECT s.sname, c.cname, sc.grade
FROM student s JOIN score sc ON s.sno = sc.sno
JOIN course c ON sc.cno = c.cno
WHERE c.cname = '数学分析';
-- 26. JOIN 连接:选修课程的学生学号姓名
SELECT DISTINCT s.sno, s.sname
FROM student s JOIN score sc ON s.sno = sc.sno;
-- 27. 自身连接:年龄大于‘刘东明’的学生
SELECT s1.sname, s1.sbirth
FROM student s1, student s2
WHERE s2.sname = '刘东明' AND s1.sbirth < s2.sbirth;
-- 28. 外部连接:未选修课程的学生
SELECT s.sno, s.sname
FROM student s LEFT JOIN score sc ON s.sno = sc.sno
WHERE sc.sno IS NULL;
-- 29. 不相关子查询:年龄大于‘刘东明’
SELECT sname, sbirth FROM student
WHERE sbirth < (SELECT sbirth FROM student WHERE sname = '刘东明');
-- 30. 未选修任何课程的学生(同28)
-- 已实现
-- 31. 比数学系所有学生年龄都大的学生
SELECT sname, sdept FROM student
WHERE sbirth < ALL(SELECT sbirth FROM student WHERE sdept = '数学');
-- 32. 选修了 004 课程的学生姓名和系
SELECT s.sname, s.sdept
FROM student s JOIN score sc ON s.sno = sc.sno
WHERE sc.cno = '004';
-- 33. 选修了“刘东明”所选全部课程的学生学号
SELECT s.sno
FROM student s
WHERE NOT EXISTS (
SELECT cno FROM score WHERE sno = '96003'
EXCEPT
SELECT cno FROM score WHERE sno = s.sno
);
-- 34. 选修了全部课程的学生学号
SELECT sno
FROM score
GROUP BY sno
HAVING COUNT(DISTINCT cno) = (SELECT COUNT(*) FROM course);
```
---
## 四、高级编程:存储过程、函数、触发器
### 1. 模糊查找存储过程
```sql
DELIMITER //
CREATE PROCEDURE pro_findname(IN keyword CHAR(1))
BEGIN
SELECT * FROM student WHERE sname LIKE CONCAT('%', keyword, '%');
END //
DELIMITER ;
```
### 2. 计算总学分函数
```sql
DELIMITER //
CREATE FUNCTION count_credit(sno_input CHAR(5))
RETURNS INT READS SQL DATA
BEGIN
DECLARE total INT DEFAULT 0;
SELECT SUM(c.credit) INTO total
FROM score sc JOIN course c ON sc.cno = c.cno
WHERE sc.sno = sno_input AND sc.grade >= 60;
RETURN IFNULL(total, 0);
END //
DELIMITER ;
```
### 3. 调用函数更新总学分的存储过程
```sql
DELIMITER //
CREATE PROCEDURE p_count_credit()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE s_no CHAR(5);
DECLARE cur CURSOR FOR SELECT sno FROM student;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
read_loop: LOOP
FETCH cur INTO s_no;
IF done THEN LEAVE read_loop; END IF;
UPDATE student SET total_credit = count_credit(s_no) WHERE sno = s_no;
END LOOP;
CLOSE cur;
END //
DELIMITER ;
```
### 4. 触发器:自动更新总学分(插入成绩时)
```sql
DELIMITER //
CREATE TRIGGER sum_credit
AFTER INSERT ON score
FOR EACH ROW
BEGIN
UPDATE student
SET total_credit = total_credit + (
SELECT credit FROM course WHERE cno = NEW.cno
)
WHERE sno = NEW.sno AND NEW.grade >= 60;
END //
DELIMITER ;
```
### 5. 级联删除触发器
```sql
DELIMITER //
CREATE TRIGGER del_student_score
AFTER DELETE ON student
FOR EACH ROW
BEGIN
DELETE FROM score WHERE sno = OLD.sno;
END //
DELIMITER ;
```
---
# 知识点
- **SQL DDL 与 DML**:掌握 `CREATE`, `ALTER`, `DROP`, `INSERT`, `UPDATE`, `DELETE` 等语句,用于数据库结构与数据操作。
- **多表连接与子查询**:理解 `JOIN`、`LEFT JOIN`、`EXISTS`、`NOT EXISTS`、`ALL` 等用于复杂查询的技术。
- **数据库编程对象**:掌握存储过程、函数、触发器的定义与使用,实现业务逻辑自动化与数据一致性。