数据库综合实验
本文最后更新于51 天前,其中的信息可能已经过时,如有错误请发送邮件到2252338560@qq.com

数据库综合实验

1.需求分析

某大型图书馆需要开发一套数字化借阅管理系统,主要业务需求如下:

图书信息:记录图书的编号、书名、作者、ISBN、出版社、出版年份、页数、语言、库存数量、单价、分类。

读者信息:记录读者的证号、姓名、性别、身份证号、出生日期、所在单位/院系、联系电话、注册日期、读者类型(学生/教师/校外)、可借数量上限。

借阅信息:记录每次借阅的流水号、读者证号、图书编号、借书日期、应还日期、实际还书日期、续借次数、逾期罚款金额。

出版社信息:记录出版社编号、出版社名称、地址、联系电话、成立年份。

分类信息:记录分类编号、分类名称、上级分类(支持树形结构)。

业务规则:

一个读者可借多本书,一本书可被多个读者在不同时间借阅。

每本书只属于一个出版社(1:n),每本书属于一个分类(1:n)。

借书时库存>0,还书时自动增加库存,逾期计算罚款(触发器实现)。

2.逻辑结构设计

2.1 关系模式:

出版社(pid, pname, address, phone, founded_year) 主码:pid

分类(cid, cname, parentid) 主码:cid 外码:parentid → category.cid

图书(bno, bname, author, isbn, pid, cid, pubyear, stock, language, price) 主码:bno 外码:pid → publisher.pid 外码:cid → category.cid

读者(rno, rname, rsex, idcard, birthday, dept, phone, regdate, rtype, maxborrow) 主码:rno

借阅(borrowid, rno, bno, borrowdate, returndate, actualdate, renew_count, fine) 主码:borrowid 外码:rno → reader.rno 外码:bno → book.bno

2.3 第三范式

出版社:3NF 分类:3NF 图书:3NF 读者:3NF 借阅:3NF

理由: 所有非主属性均完全依赖主键; 不存在部分依赖; 不存在传递依赖; 因此均满足第三范式(3NF)。

2.4 m:n转换为关系模式

m:n联系转换方法:

若两个实体之间存在多对多联系, 则建立一个新的关系模式作为联系表, 并将两个实体的主码作为外码加入联系表。

例如:

学生(Student) 课程(Course)

存在选课关系

转换为:

SC( sno, cno, score )

其中: sno为Student外码 cno为Course外码

联合主键: (sno,cno)

3.创建数据库和表

3.1创建数据库

 CREATE DATABASE library_db
 CHARACTER SET utf8mb4;
 USE library_db;

3.2创建数据库表

 CREATE TABLE book(
    bno CHAR(10) PRIMARY KEY,
    bname VARCHAR(50) NOT NULL,
    author VARCHAR(30),
    press VARCHAR(30),
    pubyear INT,
    stock INT DEFAULT 1 CHECK(stock>=0)
 );
 CREATE TABLE reader(
    rno CHAR(12) PRIMARY KEY,
    rname VARCHAR(20) NOT NULL,
    rsex CHAR(1)
         CHECK(rsex IN('男','女')),
    dept VARCHAR(40),
    phone VARCHAR(20)
 );
 CREATE TABLE borrow(
    borrowid INT AUTO_INCREMENT PRIMARY KEY,
    rno CHAR(12) NOT NULL,
    bno CHAR(10) NOT NULL,
    borrowdate DATE NOT NULL,
    returndate DATE NOT NULL,
    actualdate DATE,
     CONSTRAINT fk_reader
     FOREIGN KEY(rno)
     REFERENCES reader(rno)
     ON DELETE RESTRICT
     ON UPDATE CASCADE,
     CONSTRAINT fk_book
     FOREIGN KEY(bno)
     REFERENCES book(bno)
     ON DELETE RESTRICT
     ON UPDATE CASCADE
 );
 desc book;
 desc reader;
 desc borrow;
image-20260531161032406
image-20260531161046054
image-20260531161059619
image-20260531161113091

3.3 添加修改删除字段

 ALTER TABLE book
 ADD pages INT;
 ​
 ALTER TABLE reader
 ADD email VARCHAR(50) UNIQUE;
 ​
 验证:
 desc book
 desc reader
 ​
 ALTER TABLE book
 MODIFY author VARCHAR(50);
 ​
 ALTER TABLE reader
 MODIFY phone VARCHAR(20)
 DEFAULT '无';
 ​
 SHOW CREATE TABLE borrow;
 ALTER TABLE book
 DROP COLUMN pages;
 ​
 ALTER TABLE borrow
 DROP FOREIGN KEY fk_reader;

4.数据插入

 INSERT INTO book VALUES
 ('B001','数据库系统概论','王珊',
 '高等教育出版社',2018,5),
 ​
 ('B002','C程序设计语言','K&R',
 '机械工业出版社',2015,3),
 ​
 ('B003','三体','刘慈欣',
 '重庆出版社',2010,8),
 ​
 ('B004','计算机网络','谢希仁',
 '电子工业出版社',2018,4);
 ​
 INSERT INTO reader
 VALUES
 ('R2024001','张明','男',
 '计算机学院','13812345678',
 'zhangming@qq.com'),
 ​
 ('R2024002','李芳','女',
 '信息学院','13912345678',
 'lifang@qq.com'),
 ​
 ('R2024003','王磊','男',
 '文学院','13612345678',
 'wanglei@qq.com');
 ​
 INSERT INTO borrow VALUES
 (1,'R2024001','B001',
 '2025-03-01',
 '2025-03-15',
 '2025-03-14'),
 (2,'R2024001','B003',
 '2025-03-10',
 '2025-03-24',
 NULL),
 (3,'R2024002','B002',
 '2025-04-01',
 '2025-04-15',
 NULL),
 (4,'R2024003','B004',
 '2025-03-20',
 '2025-04-03',
 '2025-04-05');

4.1 设计违反外键约束和check约束并解释

 INSERT INTO borrow(
 rno,bno,
 borrowdate,
 returndate)
 VALUES(
 'R999999',
 'B001',
 '2025-05-01',
 '2025-05-15');
 ​
 错误:Cannot add or update a child row:
 a foreign key constraint fails
 ​
 原因:R999999在reader表中不存在,
 违反参照完整性约束。
 ​
 违反check
 INSERT INTO reader
 VALUES(
 'R2024004',
 '赵敏',
 '未知',
 '艺术学院',
 '13712345678');
 ​
 错误:Check constraint violated
 ​
 原因:rsex字段只能取
 男 或 女,
 因此违反CHECK约束。

5.数据查询(DQL-基础查询)

 1.select查询全部图书信息
 select * from book;
 2.查询库存大于3的图书
 SELECT bno,bname,stock
 FROM book
 WHERE stock > 3;
 3.查询2018年出版且库存不少于4本的图书
 SELECT bno,bname,pubyear,stock
 FROM book
 WHERE pubyear = 2018 AND stock >= 4;
 4.查询2015年至2018年出版的图书
 SELECT bno,bname,pubyear
 FROM book
 WHERE pubyear BETWEEN 2015 AND 2018;
 5.查询出版社为“重庆出版社”或“高等教育出版社”的图书
 SELECT bno,bname,press
 FROM book
 WHERE press IN('重庆出版社','高等教育出版社');
 6.查询书名中包含“计算机”的图书
 SELECT bno,bname
 FROM book
 WHERE bname LIKE '%计算机%';
 7.查询尚未归还的借阅记录
 SELECT *
 FROM borrow
 WHERE actualdate IS NULL;
 8.按库存数量降序查询图书
 SELECT bno,bname,stock
 FROM book
 ORDER BY stock DESC;
 9.查询库存最多的前2本图书
 SELECT bno,bname,stock
 FROM book
 ORDER BY stock DESC
 LIMIT 2;
 10.查询所有不同的出版社
 SELECT DISTINCT press
 FROM book;

6.数据更新(update/delete)

 1.将BOO1的库存修改为6
 UPDATE book
 SET stock = 6
 WHERE bno = 'B001';
 ​
 SELECT * FROM book WHERE bno='B001';
 2.修改张明的院系和电话
 UPDATE reader
 SET dept = '人工智能学院',
    phone = '18888888888'
 WHERE rno = 'R2024001';
 ​
 SELECT * FROM reader WHERE rno='R2024001';
 3.将2018年出版图书库存统一增加1
 UPDATE book
 SET stock = stock + 1
 WHERE pubyear = 2018;
 ​
 SELECT * FROM book WHERE pubyear=2018;
 4.删除一个测试读者
 INSERT INTO reader
 VALUES('R2024999','测试读者','男','测试学院','无');
 ​
 DELETE FROM reader
 WHERE rno = 'R2024999';
 5.事务控制:更新后回滚
 START TRANSACTION;
 ​
 UPDATE book
 SET stock = stock - 1
 WHERE bno = 'B003';
 ​
 SELECT * FROM book WHERE bno='B003';
 ​
 ROLLBACK;
 ​
 SELECT * FROM book WHERE bno='B003';

7.聚合查询与分组统计

 1.统计图书总数
 select count(*) as 图书总数 from book;
 2.统计图书库存总量
 select sum(stock) as 库存总量 from book;
 3.统计平均库存
 select avg(stock) as 平均库存 from book;
 4.查询最大库存和最小库存
 SELECT MAX(stock) AS 最大库存,
        MIN(stock) AS 最小库存
 FROM book;
 5.按出版社统计图书数量,并筛选数量大于等于1的出版社
 SELECT press, COUNT(*) AS 图书数量
 FROM book
 GROUP BY press
 HAVING COUNT(*) >= 1;

8.多表连接查询

1.等值连接:查询读者姓名和所借图书
SELECT reader.rname, book.bname
FROM reader, borrow, book
WHERE reader.rno = borrow.rno
AND borrow.bno = book.bno;
2.内连接:查询借阅记录详情
SELECT r.rname, b.bname, br.borrowdate, br.returndate
FROM borrow br
JOIN reader r ON br.rno = r.rno
JOIN book b ON br.bno = b.bno;
3.左外连接:查询所有读者及其借阅记录
SELECT r.rno, r.rname, br.borrowid, br.bno
FROM reader r
LEFT JOIN borrow br
ON r.rno = br.rno;
4.右外连接:查询所有借阅记录及读者信息
SELECT r.rname, br.borrowid, br.bno
FROM reader r
RIGHT JOIN borrow br
ON r.rno = br.rno;
5.自身连接:查询同一年出版的不同图书
SELECT a.bname AS 图书1,
b.bname AS 图书2,
a.pubyear AS 出版年份
FROM book a
JOIN book b
ON a.pubyear = b.pubyear
AND a.bno < b.bno;

9.嵌套查询

1.IN:查询借过书的读者
SELECT *
FROM reader
WHERE rno IN(
SELECT rno FROM borrow
);
2.比较运算符:查询库存大于平均库存的图书
SELECT bno,bname,stock
FROM book
WHERE stock > (
SELECT AVG(stock)
FROM book
);
3.EXISTS:查询存在借阅记录的读者
SELECT *
FROM reader r
WHERE EXISTS(
SELECT *
FROM borrow br
WHERE br.rno = r.rno
);
4.ANY:查询库存大于任意一本2018年出版图书库存的图书
SELECT bno,bname,stock
FROM book
WHERE stock > ANY(
SELECT stock
FROM book
WHERE pubyear = 2018
);
5.ALL:查询库存不少于所有图书库存的图书
SELECT bno,bname,stock
FROM book
WHERE stock >= ALL(
SELECT stock
FROM book
);

10.集合查询

1.UNION:合并读者姓名和作者姓名并去重
SELECT rname AS name
FROM reader

UNION

SELECT author AS name
FROM book;
2.UNION ALL:合并读者姓名和作者姓名,不去重
SELECT rname AS name
FROM reader

UNION ALL

SELECT author AS name
FROM book;
3.模拟 INTERSECT:查询借过书的读者证号
SELECT rno
FROM reader
WHERE rno IN(
SELECT rno
FROM borrow
);
4.模拟 EXCEPT:查询没有借书的读者
SELECT rno,rname
FROM reader
WHERE rno NOT IN(
SELECT rno
FROM borrow
);

11.视图操作

1.创建未归还图书视图
CREATE VIEW v_unreturned AS
SELECT br.borrowid, r.rname, b.bname,
br.borrowdate, br.returndate
FROM borrow br
JOIN reader r ON br.rno = r.rno
JOIN book b ON br.bno = b.bno
WHERE br.actualdate IS NULL;
2.查询视图
SELECT * FROM v_unreturned;
3.创建学生读者视图,带 WITH CHECK OPTION
CREATE VIEW v_student_reader AS
SELECT *
FROM reader
WHERE dept LIKE '%学院%'
WITH CHECK OPTION;
4.测试可更新视图
UPDATE v_student_reader
SET phone = '18800000000'
WHERE rno = 'R2024002';

说明:
该视图基于单表 reader 创建,没有聚合函数、分组和连接,因此属于可更新视图。
5.创建不可更新的聚合视图
CREATE VIEW v_press_count AS
SELECT press, COUNT(*) AS total
FROM book
GROUP BY press;

说明:
该视图使用了 GROUP BY 和 COUNT 聚合函数,因此一般不能直接更新。
6.删除视图
DROP VIEW v_unreturned;
DROP VIEW v_student_reader;
DROP VIEW v_press_count;

12.索引

1.创建普通索引
CREATE INDEX idx_book_bname
ON book(bname);
2.创建唯一索引
CREATE UNIQUE INDEX idx_reader_phone
ON reader(phone);
3.创建复合索引
CREATE INDEX idx_borrow_rno_bno
ON borrow(rno,bno);
查看索引
SHOW INDEX FROM book;
SHOW INDEX FROM reader;
SHOW INDEX FROM borrow;
删除索引
DROP INDEX idx_book_bname ON book;
DROP INDEX idx_reader_phone ON reader;
DROP INDEX idx_borrow_rno_bno ON borrow;

13.数据完整性约束验证与级联操作

1.实体完整性验证:主键不能为空
INSERT INTO book(bno,bname,author,press,pubyear,stock)
VALUES(NULL,'测试书','测试作者','测试出版社',2020,1);

说明:
bno 是 book 表主键,主键不能为空,因此插入失败。
2.参照完整性验证:插入不存在的图书编号
INSERT INTO borrow(rno,bno,borrowdate,returndate,actualdate)
VALUES('R2024001','B999','2025-05-01','2025-05-15',NULL);

说明:
B999 在 book 表中不存在,borrow.bno 是外键,因此违反参照完整性。
3.用户定义完整性验证:库存不能小于0
UPDATE book
SET stock = -1
WHERE bno = 'B001';

说明:
stock 字段设置了 CHECK(stock>=0),库存不能为负数。
4.用户定义完整性验证:库存不能小于0
UPDATE book
SET stock = -1
WHERE bno = 'B001';

说明:
stock 字段设置了 CHECK(stock>=0),库存不能为负数。
5.ON UPDATE CASCADE 测试
UPDATE reader
SET rno = 'R2024999'
WHERE rno = 'R2024003';

SELECT * FROM borrow
WHERE rno = 'R2024999';

说明:
reader.rno 更新后,borrow 表中对应的外键 rno 会自动同步更新。

14.触发器

准备:删除旧触发器
DROP TRIGGER IF EXISTS trg_borrow_before_insert;
DROP TRIGGER IF EXISTS trg_return_after_update;
DROP TRIGGER IF EXISTS trg_reader_before_delete;
创建删除读者日志表
CREATE TABLE reader_delete_log(
logid INT AUTO_INCREMENT PRIMARY KEY,
rno CHAR(12),
rname VARCHAR(20),
dept VARCHAR(40),
delete_time DATETIME DEFAULT CURRENT_TIMESTAMP
);
1.借书时自动减少库存
DELIMITER //

CREATE TRIGGER trg_borrow_before_insert
BEFORE INSERT ON borrow
FOR EACH ROW
BEGIN
DECLARE v_stock INT;

SELECT stock INTO v_stock
FROM book
WHERE bno = NEW.bno;

IF v_stock <= 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '库存不足,不能借书';
ELSE
UPDATE book
SET stock = stock - 1
WHERE bno = NEW.bno;
END IF;
END //

DELIMITER ;

测试:

SELECT stock FROM book WHERE bno='B003';

INSERT INTO borrow(rno,bno,borrowdate,returndate,actualdate)
VALUES('R2024002','B003','2025-05-01','2025-05-15',NULL);

SELECT stock FROM book WHERE bno='B003';
2.还书时自动增加库存并计算罚款
DELIMITER //

CREATE TRIGGER trg_return_after_update
AFTER UPDATE ON borrow
FOR EACH ROW
BEGIN
IF OLD.actualdate IS NULL AND NEW.actualdate IS NOT NULL THEN

UPDATE book
SET stock = stock + 1
WHERE bno = NEW.bno;

UPDATE borrow
SET fine =
CASE
WHEN NEW.actualdate > NEW.returndate
THEN DATEDIFF(NEW.actualdate, NEW.returndate) * 1
ELSE 0
END
WHERE borrowid = NEW.borrowid;

END IF;
END //

DELIMITER ;

测试:

UPDATE borrow
SET actualdate = '2025-05-18'
WHERE rno='R2024002'
AND bno='B003'
AND borrowdate='2025-05-01';

SELECT * FROM borrow
WHERE rno='R2024002'
AND bno='B003';

SELECT stock FROM book WHERE bno='B003';
3.删除读者前记录日志
DELIMITER //

CREATE TRIGGER trg_reader_before_delete
BEFORE DELETE ON reader
FOR EACH ROW
BEGIN
INSERT INTO reader_delete_log(rno,rname,dept)
VALUES(OLD.rno, OLD.rname, OLD.dept);
END //

DELIMITER ;

测试:

INSERT INTO reader
VALUES('R2024888','日志测试','男','测试学院','无');

DELETE FROM reader
WHERE rno='R2024888';

SELECT * FROM reader_delete_log;

15.数据安全性

1.创建用户并授予查询权限
CREATE USER 'lib_user1'@'localhost'
IDENTIFIED BY '123456';

GRANT SELECT
ON library_db.book
TO 'lib_user1'@'localhost';

查看权限:
SHOW GRANTS FOR 'lib_user1'@'localhost';
2.授予权限并允许转授权
GRANT SELECT, INSERT
ON library_db.reader
TO 'lib_user1'@'localhost'
WITH GRANT OPTION;

说明:
WITH GRANT OPTION 表示该用户可以将自己拥有的权限再授予其他用户。
3.回收权限
REVOKE INSERT
ON library_db.reader
FROM 'lib_user1'@'localhost';
4.创建角色并授权
CREATE ROLE 'reader_role';

GRANT SELECT
ON library_db.*
TO 'reader_role';

CREATE USER 'lib_user2'@'localhost'
IDENTIFIED BY '123456';

GRANT 'reader_role'
TO 'lib_user2'@'localhost';

SET DEFAULT ROLE 'reader_role'
TO 'lib_user2'@'localhost';

16.视图与派生表

1.带聚合函数的视图:统计每个读者借阅次数
CREATE VIEW v_reader_borrow_count AS
SELECT r.rno, r.rname, COUNT(br.borrowid) AS borrow_count
FROM reader r
LEFT JOIN borrow br
ON r.rno = br.rno
GROUP BY r.rno, r.rname;

查询:

SELECT * FROM v_reader_borrow_count;
2.派生表:查询借阅次数大于1的读者
SELECT *
FROM (
SELECT rno, COUNT(*) AS borrow_count
FROM borrow
GROUP BY rno
) AS t
WHERE t.borrow_count > 1;
3.WITH 子句统计每位读者借阅数量
WITH reader_count AS (
SELECT rno, COUNT(*) AS total
FROM borrow
GROUP BY rno
)
SELECT r.rno, r.rname, rc.total
FROM reader r
LEFT JOIN reader_count rc
ON r.rno = rc.rno;
4.WITH 子句:查询未归还图书
WITH unreturned AS (
SELECT br.borrowid, r.rname, b.bname,
br.borrowdate, br.returndate
FROM borrow br
JOIN reader r ON br.rno = r.rno
JOIN book b ON br.bno = b.bno
WHERE br.actualdate IS NULL
)
SELECT * FROM unreturned;

17.扩展思考

  1. 如何处理分类实体的自关联?
分类实体存在“上级分类”和“下级分类”的关系,因此可以在 category 表中设置 parentid 字段。

category(
cid,
cname,
parentid
)

其中 cid 是分类编号,parentid 是上级分类编号,同时 parentid 也是指向 category.cid 的外键。

如果某分类没有上级分类,则 parentid 可以为空。
这种设计可以表示树形结构,例如:

图书
├── 计算机
│ ├── 数据库
│ └── 网络技术
└── 文学
└── 科幻小说

2. 借阅关系是否可能存在数据冗余?

借阅表如果只保存 rno、bno、borrowdate、returndate、actualdate 等信息,则冗余较少。

但是如果在 borrow 表中同时保存读者姓名 rname、图书名称 bname、出版社 press 等信息,就会产生数据冗余。

例如:
borrow(borrowid, rno, rname, bno, bname, borrowdate)

其中 rname 依赖 rno,bname 依赖 bno,而不是直接依赖 borrowid,会产生传递依赖。

规范化方案:
将读者信息保存在 reader 表;
将图书信息保存在 book 表;
borrow 表只保存读者证号和图书编号作为外键。

3. 如何防止库存为负数?

可以从两个方面防止库存为负数:

第一,在 book 表中设置 CHECK(stock >= 0) 约束,保证库存不能小于0。

第二,在借书触发器中判断库存数量。
当插入 borrow 借阅记录时,先查询图书库存。
如果库存小于等于0,则使用 SIGNAL 抛出错误,阻止借书操作;
如果库存大于0,则允许借阅,并自动将库存减1。

这样可以保证借书时不会出现库存为负数的情况。

4. 预约图书功能需要增加哪些实体和关系?

如果系统支持预约图书功能,可以增加 reservation 预约表。

reservation(
reserveid,
rno,
bno,
reservedate,
status
)

其中:
reserveid 表示预约编号;
rno 是读者证号,外键引用 reader.rno;
bno 是图书编号,外键引用 book.bno;
reservedate 表示预约日期;
status 表示预约状态,如“预约中”“已取消”“已完成”。

新增关系:
一个读者可以预约多本图书;
一本图书可以被多个读者预约;
读者和图书之间通过 reservation 表形成 m:n 联系。

5. 为什么遵循最小权限原则?

最小权限原则是指只给用户完成工作所必需的权限,不授予多余权限。

在本实验中,如果某用户只负责查询图书信息,则只授予 SELECT 权限即可,不应该授予 INSERT、UPDATE、DELETE 等权限。

例如:

GRANT SELECT ON library_db.book TO 'lib_user1'@'localhost';

这样可以防止用户误删、误改数据,提高数据库安全性。
如果后续不再需要某项权限,还可以使用 REVOKE 回收权限。

6. 并发借阅库存仅剩1本的图书会产生什么问题?如何解决?

当多用户同时借阅同一本库存仅剩1本的图书时,可能出现超卖问题。

例如两个用户同时读取库存 stock=1,都认为可以借阅,然后同时插入借阅记录并执行库存减1,最终可能导致库存异常或出现超额借阅。

解决方法:
1. 使用事务保证借书操作的原子性;
2. 使用 SELECT ... FOR UPDATE 对图书库存记录加行级锁;
3. 在触发器中判断库存是否大于0;
4. 给 stock 字段设置 CHECK(stock >= 0) 约束。

示例:

START TRANSACTION;

SELECT stock
FROM book
WHERE bno='B001'
FOR UPDATE;

UPDATE book
SET stock = stock - 1
WHERE bno='B001'
AND stock > 0;

INSERT INTO borrow(rno,bno,borrowdate,returndate)
VALUES('R2024001','B001','2025-05-01','2025-05-15');

COMMIT;

这样可以避免多个用户同时修改库存导致数据不一致。

实验总结

 通过本次图书借阅管理系统综合实验,我系统地完成了数据库设计与实现的全过程。实验从需求分析开始,逐步完成 E-R 图设计、关系模式转换、物理表结构设计、数据插入、查询操作、视图、索引、完整性约束、触发器和权限管理等内容,使我对数据库应用系统的设计流程有了更加完整的认识。
 ​
 在实验过程中,我首先根据图书馆业务需求分析出图书、读者、借阅、出版社、分类等实体,并明确了它们之间的联系类型。例如,出版社与图书之间是一对多关系,分类与图书之间是一对多关系,读者与图书之间通过借阅表形成多对多关系。通过 E-R 图设计,我进一步理解了概念结构设计在数据库开发中的重要作用。
 ​
 在逻辑结构设计阶段,我将 E-R 图转换为关系模式,并分析各表是否满足第三范式。通过规范化设计,避免了在借阅表中重复保存读者姓名、图书名称等信息,减少了数据冗余,提高了数据一致性。在物理设计阶段,我使用 SQL 创建数据库和数据表,设置了主键、外键、非空、默认值和 CHECK 约束,对实体完整性、参照完整性和用户定义完整性有了更深刻的理解。
 ​
 在数据操作部分,我练习了 INSERT、UPDATE、DELETE 和 SELECT 语句,并完成了基础查询、聚合查询、多表连接查询、嵌套查询和集合查询等内容。通过这些练习,我掌握了 SQL 查询语句的常见写法,尤其是多表连接和嵌套查询的使用方法。实验中还创建了视图和索引,理解了视图可以简化复杂查询,索引可以提高查询效率,但也会增加维护成本。
 ​
 在触发器部分,我实现了借书自动减少库存、还书自动增加库存并计算罚款、删除读者前记录日志等功能。通过触发器实验,我认识到数据库不仅可以存储数据,还可以在特定操作发生时自动执行一些业务逻辑。实验过程中也遇到了一些问题,例如外键约束导致数据无法删除、CHECK 约束插入失败、触发器语法错误等。通过查看错误信息、修改 SQL 语句和反复测试,最终解决了这些问题。
 ​
 通过本次实验,我不仅巩固了数据库理论知识,也提高了 SQL 编写能力和数据库调试能力。今后在设计数据库系统
文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇