软件版本说明:
1.Mysql数据库:sql server8.0
2.命令实现使用以及数据库可视化查看:Navicat 16
#不用Mysql Command Line 的原因是不喜欢那个黑框,也不常用,使用Navicat的MYSQL命令列界面是一样的
另外说明 实现相同的效果可能有很多种SQL语句,我的答案只是一种参考,不一定是最简单有效的哦
实验任务要求:
一、建表、插入数据
建立校级创新项目数据库的四个基本表并用INSERT 语句输入数据:
注意:
- 一个教师能负责多个项目
- 一个项目只能有一名指导老师,能有多名学生参与
- 一个学生能选择多个项目;
建表要求:
- 注意实体完整性约束以及参照完整性约束;
- 自定义完整性:性别约束,成绩约束(Grade在0~100之间);
- 成绩、年龄为int,其余均为char。
S(Sno,Sname,Ssex,Sage,Sdept) 学生(学号,姓名,性别,年龄,系)
T(Tno,Tname, Tsex,Tdept) 教师(教师编号,教师姓名,教师所在系)
P(Pno,Pname,Tno) 项目(项目编号,项目名称,指导教师编号)
SP(Sno,Pno,Grade) 参与情况(学号,项目编号,成绩)
//代码块1 建立学生表S及运行结果
mysql> CREATE TABLE S(Sno CHAR(5) PRIMARY KEY,
Sname char(10),
Ssex char(2) check(Ssex in('男','女')),
Sage int check(Sage between 0 and 100),
Sdept char(2));
Query OK, 0 rows affected (0.02 sec)
//代码块2 建立教师表T及运行结果
mysql> CREATE TABLE T(Tno char(3) PRIMARY KEY,
Tname char(10),
Tsex char(2) CHECK(Tsex in('男','女')),
Tdept char(2));
Query OK, 0 rows affected (0.02 sec)
//代码块3 建立项目P表及运行结果
mysql> CREATE TABLE P (
Pno CHAR(5) PRIMARY KEY,
Pname CHAR(20),
Tno CHAR(5),
FOREIGN KEY (Tno) REFERENCES T(Tno)
);
Query OK, 0 rows affected (0.05 sec)
//代码块4 建立参与情况表SP
mysql> CREATE TABLE SP(
Sno char(6),
Pno char(5),
Grade int check(Grade between 0 and 100),
foreign key (Sno) references S(Sno),
foreign key (Pno) references P(Pno),
primary key(Sno,Pno));
Query OK, 0 rows affected (0.03 sec)
S表数据如下:
'23121', '韩刚', '男', 20, 'CS'
'23122', '刘心语', '女', 19, 'CS'
'23123', '苏恬', '女', 19, 'CS'
'23124', '潘佳慧', '女', 19, 'CS'
'23125', '邓辉', '男', 20, 'CS'
'23126', '肖馨玥', '女', 19, 'CS'
'23127', '薛志超', '男', 20, 'CS'
'23128', '迪丽', '女', 19, 'CS'
'23201',‘罗钧一’,‘男’,20,‘MA’
'23202', '王浩然', '男', 18, 'MA'
'23203',‘马杰’,‘男’,20,‘MA’
'23204, '蔡静雯', '女', 18, 'MA'
'23205',‘刘雪彤’,‘女’,20,‘MA’
'23206', '丁一', '女', 18, 'MA'
'23321', '张立', '男', 19, 'IS'
'23322', '杨娜', '女', 19, 'IS'
//代码块5 插入学生表S信息及运行结果
mysql> INSERT INTO S VALUES ('23121', '韩刚', '男', 20, 'CS'),
('23122', '刘心语', '女', 19, 'CS'),
('23123', '苏恬', '女', 19, 'CS'),
('23124', '潘佳慧', '女', 19, 'CS'),
('23125', '邓辉', '男', 20, 'CS'),
('23126', '肖馨玥', '女', 19, 'CS'),
('23127', '薛志超', '男', 20, 'CS'),
('23128', '迪丽', '女', 19, 'CS'),
('23201', '罗钧一', '男', 20, 'MA'),
('23202', '王浩然', '男', 18, 'MA'),
('23203', '马杰', '男', 20, 'MA'),
('23204', '蔡静雯', '女', 18, 'MA'),
('23205', '刘雪彤', '女', 20, 'MA'),
('23206', '丁一', '女', 18, 'MA'),
('23321', '张立', '男', 19, 'IS'),
('23322', '杨娜', '女', 19, 'IS');
Query OK, 16 rows affected (0.02 sec)
Records: 16 Duplicates: 0 Warnings: 0
T表数据如下:
'101', '梁任甫', 'CS'
'102', '陈鹤寿', 'CS'
'103', '王静安', 'MA'
'104', '赵宜仲', ‘IS’
//代码块6 插入教师表
mysql> INSERT INTO T VALUES
('101', '梁任甫', '男', 'CS'),
('102', '陈鹤寿', '男', 'CS'),
('103', '王静安', '女', 'MA'),
('104', '赵宜仲', '男', 'IS');
Query OK, 4 rows affected (0.01 sec)
Records: 4 Duplicates: 0 Warnings: 0
P表数据如下:
'1', '数据库设计项目', '101'
'2', '无人机飞行设计项目', '103'
'3', '校园网络规划项目, '102'
'4', '操作系统设计项目', '101'
'5', '视觉处理项目', '102'
'6', '大模型构建项目', ‘104’
//7插入项目表
mysql> INSERT INTO P VALUES ('1', '数据库设计项目', '101'),
('2', '无人机飞行设计项目', '103'),
('3', '校园网络规划项目', '102'),
('4', '操作系统设计项目', '101'),
('5', '视觉处理项目', '102'),
('6', '大模型构建项目', '104');
Query OK, 6 rows affected (0.01 sec)
Records: 6 Duplicates: 0 Warnings: 0
SP表(可自行补充数据):
'23122', '3', 80
'23122', '2', 90
'23121', '3', 88
'23122', '5', 68
'23123', '1', 92
'23124', '2', 85
'23125', '5', 94
'23126', '3', 88
'23201', '1', 92
'23202', '1', 92
'23202', '6', 77
'23203', '2', 79
'23204', '4', 85
'23122', '6', 90
'23205', '3', 99
'23206', '5', 58
'23321', '1', 55
'23321', '6', 81
'23322', '6', 89
'23322', '2', 75
'23128', '4', 81
'23127', '4', 89
'23128', '1', 88
'23122', '1', 75
'23122', '4', 80
//代码块8 插入参与情况表
mysql> INSERT INTO SP VALUES
('23122', '3', 80),
('23122', '2', 90),
('23121', '3', 88),
('23122', '5', 68),
('23123', '1', 92),
('23124', '2', 85),
('23125', '5', 94),
('23126', '3', 88),
('23201', '1', 92),
('23202', '1', 92),
('23202', '6', 77),
('23203', '2', 79),
('23204', '4', 85),
('23122', '6', 90),
('23205', '3', 99),
('23206', '5', 58),
('23321', '1', 55),
('23321', '6', 81),
('23322', '6', 89),
('23322', '2', 75),
('23128', '4', 81),
('23127', '4', 89),
('23128', '1', 88),
('23122', '1', 75),
('23122', '4', 80);
Query OK, 25 rows affected (0.01 sec)
Records: 25 Duplicates: 0 Warnings: 0
- 建表
- 建立四个基本表
- 用INSERT插入数据,SP表可自行补充数据,
二、查询
1. 查询参与 3 号项目的学生学号与该课程成绩。
mysql> SELECT Sno,Grade FROM SP WHERE Pno=3;
+-------+-------+
| Sno | Grade |
+-------+-------+
| 23121 | 88 |
| 23122 | 80 |
| 23126 | 88 |
| 23205 | 99 |
+-------+-------+
4 rows in set (0.03 sec)
2. 查询负责项目名为'无人机飞行设计项目'的教师姓名。
mysql> select Tname FROM P,T
WHERE T.Tno=P.Tno and Pname='无人机飞行设计项目';
+--------+
| Tname |
+--------+
| 王静安 |
+--------+
1 row in set (0.03 sec)
mysql> SELECT T.Tname FROM T
JOIN P ON T.Tno = P.Tno
WHERE Pname = '无人机飞行设计项目';
+--------+
| Tname |
+--------+
| 王静安 |
+--------+
1 row in set (0.02 sec)
3. 查询没有参与 2 号项目的学生姓名与专业。
mysql> select S.Sname,S.Sdept from S
WHERE Sno not in
(select Sno from SP where Pno=2);
+--------+-------+
| Sname | Sdept |
+--------+-------+
| 韩刚 | CS |
| 苏恬 | CS |
| 邓辉 | CS |
| 肖馨玥 | CS |
| 薛志超 | CS |
| 迪丽 | CS |
| 罗钧一 | MA |
| 王浩然 | MA |
| 蔡静雯 | MA |
| 刘雪彤 | MA |
| 丁一 | MA |
| 张立 | IS |
+--------+-------+
12 rows in set (0.04 sec)
这里where里面的Sno如果写为S.Sno,那么结果就会有很多重复的相同结果,需要在select后面加distinct才会得到同样的输出,但是这样效率低,花费时间为0.05sec。原理是如果用的S.Sno,是把所有的Sno一起,挨个和选择出的not in 结果比较,每比较一次得到一些结果后就再拿全部Sno去比较下一个not in 结果(一个学生可以多个项目),所以会有重复出现的结果
4. 查询参加了所有项目的学生姓名。
mysql> SELECT S.Sname
FROM S
WHERE NOT EXISTS (
SELECT *
FROM P
WHERE NOT EXISTS (
SELECT *
FROM SP
WHERE SP.Sno = S.Sno AND SP.Pno = P.Pno
)
);
+--------+
| Sname |
+--------+
| 刘心语 |
+--------+
1 row in set (0.03 sec)
这个还挺难写的
5. 查询只参加一个项目的学生的学号。
mysql> select Sno from
(select Sno,count(*) as p_count from SP GROUP BY Sno) as p_counts
where p_count=1;
+-------+
| Sno |
+-------+
| 23121 |
| 23123 |
| 23124 |
| 23125 |
| 23126 |
| 23127 |
| 23201 |
| 23203 |
| 23204 |
| 23205 |
| 23206 |
+-------+
11 rows in set (0.03 sec)
mysql> SELECT Sno
FROM SP
GROUP BY Sno
HAVING COUNT(*) = 1;
+-------+
| Sno |
+-------+
| 23121 |
| 23123 |
| 23124 |
| 23125 |
| 23126 |
| 23127 |
| 23201 |
| 23203 |
| 23204 |
| 23205 |
| 23206 |
+-------+
11 rows in set (0.08 sec)
每一个派生的关系都需要起一个别名,比如这里的p_count和p_counts
6. 查询所有项目成绩均及格的学生的学号和平均成绩,其结果按平均成绩的降序排列。(平均成绩:参与项目成绩/参与项目数)
mysql> SELECT Sno, AVG(Grade) AS 平均成绩
FROM SP
GROUP BY Sno
HAVING MIN(Grade) >= 60
ORDER BY 平均成绩 DESC;
+-------+----------+
| Sno | 平均成绩 |
+-------+----------+
| 23205 | 99.0000 |
| 23125 | 94.0000 |
| 23123 | 92.0000 |
| 23201 | 92.0000 |
| 23127 | 89.0000 |
| 23121 | 88.0000 |
| 23126 | 88.0000 |
| 23124 | 85.0000 |
| 23204 | 85.0000 |
| 23128 | 84.5000 |
| 23202 | 84.5000 |
| 23322 | 82.0000 |
| 23122 | 80.5000 |
| 23203 | 79.0000 |
+-------+----------+
14 rows in set (0.04 sec)
要查询所有项目成绩均及格的学生的学号和平均成绩,首先需要计算每个学生的平均成绩,然后筛选出平均成绩均及格的学生,并按平均成绩的降序排列。
SELECT Sno, AVG(Grade) AS 平均成绩 FROM SP GROUP BY Sno HAVING MIN(Grade) >= 60 ORDER BY 平均成绩 DESC;
这个查询首先按学号分组,然后计算每个学生的平均成绩。接着使用HAVING子句过滤出平均成绩均大于等于60分的学生,并按平均成绩的降序排列。
7. 查询参与1号项目,且成绩排名第2的学生姓名。(成绩相同按相同名次处理,比如88,88,85,则85为第2名)
mysql> SELECT S.Sname
FROM S
JOIN SP ON S.Sno = SP.Sno
WHERE Pno = 1
ORDER BY Grade DESC
LIMIT 1 OFFSET 1;
+--------+
| Sname |
+--------+
| 罗钧一 |
+--------+
1 row in set (0.06 sec)
mysql> SELECT S.Sname
FROM S
JOIN SP ON S.Sno = SP.Sno
WHERE Pno = 1
ORDER BY Grade DESC
LIMIT 1,1;
+--------+
| Sname |
+--------+
| 罗钧一 |
+--------+
1 row in set (0.04 sec)
三、数据修改、删除与视图
1. 把4号项目的成绩降低5%。
mysql> update SP set Grade=Grade*0.95 where Pno=4;
Query OK, 4 rows affected (0.02 sec)
Rows matched: 4 Changed: 4 Warnings: 0
2. 在P表和 SP表中删除项目号为5的所有数据。(删除后做回滚处理)
//因为之前执行过语句了,所以被影响的行是0
mysql> START TRANSACTION;
DELETE FROM P WHERE Pno = 5;
DELETE FROM SP WHERE Pno = 5;
ROLLBACK;
Query OK, 0 rows affected (0.01 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
3. 建立女学生的视图,属性包括学号、姓名、参与项目名字和成绩。
mysql> CREATE VIEW Femal_Student AS
SELECT S.Sno, S.Sname,P.Pname,SP.Grade
from S
join SP ON S.Sno=SP.Sno
JOIN P on SP.Pno=P.Pno
WHERE S.Ssex='女';
Query OK, 0 rows affected (0.01 sec)
4. 在女学生视图中查询平均成绩大于 80 分的学生学号与姓名。
mysql> select Sno,Sname from Femal_Student group by Sname,Sno having AVG(Grade)>80;
+-------+--------+
| Sno | Sname |
+-------+--------+
| 23122 | 刘心语 |
| 23123 | 苏恬 |
| 23124 | 潘佳慧 |
| 23126 | 肖馨玥 |
| 23128 | 迪丽 |
| 23204 | 蔡静雯 |
| 23205 | 刘雪彤 |
| 23322 | 杨娜 |
+-------+--------+
8 rows in set (0.07 sec)
5. 建立成绩视图,计算每个学生的参与项目数目、平均成绩。
mysql> CREATE VIEW Grade_View AS
SELECT Sno,COUNT(Pno) as 参与项目数, avg(grade) as 平均成绩
from SP group by Sno;
Query OK, 0 rows affected (0.01 sec)
6. 使用 GRANT 语句,把对基本表 SP 的所有权限,S,P,T表的查询权限授给Root3。
mysql> create user Root3;
Query OK, 0 rows affected (0.01 sec)
//先创建了Root3
mysql> GRANT ALL ON SP TO Root3;
Query OK, 0 rows affected (0.01 sec)
mysql> GRANT SELECT ON S TO Root3;
Query OK, 0 rows affected (0.01 sec)
mysql> GRANT SELECT ON P TO Root3;
Query OK, 0 rows affected (0.01 sec)
mysql> GRANT SELECT ON T TO Root3;
Query OK, 0 rows affected (0.01 sec)
四、触发器
1.首先解除S表和SP表的参照关系。然后在Student表上创建一个触发器,使更新一个学生的学号信息时能够级联的更新此学生在SP表中的学号信息,并进行验证。
mysql> alter table SP drop foreign key SP_ibfk_1;
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> CREATE TRIGGER Update_SP_Sno
after update on s
for each row
begin
UPDATE SP
SET Sno=NEW.Sno
where Sno=old.Sno;
end;
Query OK, 0 rows affected (0.01 sec)
mysql> select Sno from S ;
+-------+
| Sno |
+-------+
| 23121 |
| 23122 |
| 23123 |
| 23124 |
| 23125 |
| 23126 |
| 23127 |
| 23128 |
| 23201 |
| 23202 |
| 23203 |
| 23204 |
| 23205 |
| 23206 |
| 23321 |
| 23322 |
+-------+
16 rows in set (0.03 sec)
mysql> select DISTINCT Sno from SP ;
+-------+
| Sno |
+-------+
| 23121 |
| 23122 |
| 23123 |
| 23124 |
| 23126 |
| 23127 |
| 23128 |
| 23201 |
| 23202 |
| 23203 |
| 23204 |
| 23205 |
| 23321 |
| 23322 |
+-------+
14 rows in set (0.04 sec)
mysql> UPDATE S SET Sno='11111' WHERE Sno='23121';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select Sno from S ;
+-------+
| Sno |
+-------+
| 11111 |
| 23122 |
| 23123 |
| 23124 |
| 23125 |
| 23126 |
| 23127 |
| 23128 |
| 23201 |
| 23202 |
| 23203 |
| 23204 |
| 23205 |
| 23206 |
| 23321 |
| 23322 |
+-------+
16 rows in set (0.03 sec)
mysql> select DISTINCT Sno from SP ;
+-------+
| Sno |
+-------+
| 11111 |
| 23122 |
| 23123 |
| 23124 |
| 23126 |
| 23127 |
| 23128 |
| 23201 |
| 23202 |
| 23203 |
| 23204 |
| 23205 |
| 23321 |
| 23322 |
+-------+
14 rows in set (0.03 sec)
// 删除外键
mysql> UPDATE S SET Sno='22222' WHERE Sno='11111';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select Sno from S ;
+-------+
| Sno |
+-------+
| 22222 |
| 23122 |
| 23123 |
| 23124 |
| 23125 |
| 23126 |
| 23127 |
| 23128 |
| 23201 |
| 23202 |
| 23203 |
| 23204 |
| 23205 |
| 23206 |
| 23321 |
| 23322 |
+-------+
16 rows in set (0.03 sec)
mysql> select DISTINCT Sno from SP ;
+-------+
| Sno |
+-------+
| 11111 |
| 23122 |
| 23123 |
| 23124 |
| 23126 |
| 23127 |
| 23128 |
| 23201 |
| 23202 |
| 23203 |
| 23204 |
| 23205 |
| 23321 |
| 23322 |
+-------+
14 rows in set (0.03 sec)
//为了验证触发器,先将SP表的'11111'手动改为'22222'
UPDATE SP SET Sno='22222' WHERE Sno='11111';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select DISTINCT Sno from SP ;
+-------+
| Sno |
+-------+
| 22222 |
| 23122 |
| 23123 |
| 23124 |
| 23126 |
| 23127 |
| 23128 |
| 23201 |
| 23202 |
| 23203 |
| 23204 |
| 23205 |
| 23321 |
| 23322 |
+-------+
14 rows in set (0.03 sec)
//此时数据相同但是没有关联
mysql> CREATE TRIGGER Update_SP_Sno
after update on s
for each row
begin
UPDATE SP
SET Sno=NEW.Sno
where Sno=old.Sno;
end;
Query OK, 0 rows affected (0.01 sec)
mysql> UPDATE S SET Sno='23121' WHERE Sno='22222';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select DISTINCT Sno from S ;
+-------+
| Sno |
+-------+
| 23121 |
| 23122 |
| 23123 |
| 23124 |
| 23125 |
| 23126 |
| 23127 |
| 23128 |
| 23201 |
| 23202 |
| 23203 |
| 23204 |
| 23205 |
| 23206 |
| 23321 |
| 23322 |
+-------+
16 rows in set (0.03 sec)
mysql> select DISTINCT Sno from SP ;
+-------+
| Sno |
+-------+
| 23121 |
| 23122 |
| 23123 |
| 23124 |
| 23126 |
| 23127 |
| 23128 |
| 23201 |
| 23202 |
| 23203 |
| 23204 |
| 23205 |
| 23321 |
| 23322 |
+-------+
14 rows in set (0.03 sec)
2.在 S 表中编写 insert 的触发器,假如表的学生不能超过 18个,如果低于此数,添加可以完成;如果超过此数,则插入将不能实现。进行验证。
mysql> CREATE TRIGGER Check_Student_Count
BEFORE INSERT ON S
FOR EACH ROW
BEGIN
DECLARE student_count INT;
SELECT COUNT(*) INTO student_count FROM S;
IF student_count >= 18 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '学生数量已达上限';
END IF;
END;
Query OK, 0 rows affected (0.01 sec)
mysql> insert into S values('88888','何何','男',22,'CS');
Query OK, 1 row affected (0.01 sec)
mysql> insert into S values('88889','何何','男',22,'CS');
Query OK, 1 row affected (0.00 sec)
mysql> insert into S values('88890','何何','男',22,'CS');
1644 - 学生数量已达上限
3.在 SP 表上编写 update 触发器,当修改 SP表中的 Grade 字段时将其修改前后的信息保存在 SC_log 表中。实验完成后,撤消建立的基本表和视图。
mysql> CREATE TABLE SC_log (
Sno INT,
Pno INT,
Old_Grade INT,
New_Grade INT
);
CREATE TRIGGER Update_Grade_Log
AFTER UPDATE ON SP
FOR EACH ROW
BEGIN
INSERT INTO SC_log (Sno, Pno, Old_Grade, New_Grade)
VALUES (OLD.Sno, OLD.Pno, OLD.Grade, NEW.Grade);
END;
Query OK, 0 rows affected (0.02 sec)
Query OK, 0 rows affected (0.00 sec)