第1章 设计背景与需求分析
1.1 设计背景
1.1.1  图书管理的现状  

图书馆作为一种资源的集散地,图书和用户在借阅资料繁多,包含很多的信息管理,现在有很多的图书馆都是初步的开始使用,甚至尚未使用计算机进行资源管理,没有建立相对应的图书管理数据系统,而是使用人工计算,抄写进行,数据处理工作量大,容易出错和数据丢失。      

1.2.2  选题的目的、意义   

图书管理系统数据库有着手工管理无法比拟的优点,如检索迅速、查找方便、可靠性高、存储量大、保密性好,成本低等等。这些优点能极大提高图书管理的效率,因此,开发一套能够为用户提供充足的信息和快捷的查询手段的图书管理系统是十分必要的。

1.2 功能需求
1.2.1读者信息的增加、修改、删除等基本操作

1.读者类别信息的输入,包括图书类型、图书册数等

2.读者档案信息的输入,包括读者编号、读者类型等

1.2.2图书信息的增加、修改、删除等基本操作。

1.图书类别信息的输入,包括类别编号,类别名称等。

2.图书类别信息的查询,修改,包括类别编号,类别名称等。

3.图书档案信息的输入,包括图书编号,图书名称,图书类别,作者名称,出版社名称,出版日期,图书页数,关键词,登记日期,备注信息等。

1.2.3图书流通管理

          1.图书征订管理

          2.图书借阅管理

          3.图书归还管理

          4.图书罚款管理

1.3 系统开发环境
1、系统:Windows XP,7,8,10

2、开发平台:SQL SERVER 2070, VISUAL BASIC6.0

1.4 SQL SERVER 2017概述
SQL SERVER2017是一个关系数据管理系统,是微软公司推出的新版本,该版本增加了许多先进的功能,具有方便使用,可伸缩性好与软件集成度高等的优点,可以运行在个人电脑到大型多处理器的服务器等多种平台使用。

官网下载说明https://www.microsoft.com/zh-cn/sql-server/sql-server-2017-comparison

第2章 数据库概念结构设计
2.1 实体型结构

  https://blog.csdn.net/weixin_45031801/article/details/137796214?spm=1001.2100.3001.7377&utm_medium=distribute.pc_feed_blog_category.none-task-blog-classify_tag-4-137796214-null-null.nonecase&depth_1-utm_source=distribute.pc_feed_blog_category.none-task-blog-classify_tag-4-137796214-null-null.nonecase

2.2 实体间的联系
      1.一个出版社对应多个图书,一个图书对应一个出版社,出版社和图书是一对多联系。

      2.一个图书类型对应多个图书,一个图书对应一个图书类型,图书类型和图书是一对多联系。

      3.一个读者类型对应多个读者,一个读者对应一个读者类型,读者类型和读者是一对多联系。

      4.一个书库对应多个图书类型,一个图书类型对应一个书库,书库和图书类型是一对多联系。

      5.一个图书入库单对应多个图书入库单明细,一个图书入库单明细对应一个图书入库单,图书入库单和图书入库单明细是一对多联系。

      6.一个图书报损单对应多个图书报损单明细,一个图书报损单明细对于一个图书报损单,图书报损单和图书报损单明细是一对多联系。

      7.一个读书对应多个图书入库单明细,一个图书入库单明细对应一个图书,图书和图书入库单明细是一对多联系。

      8.一个读书对应多个图书报损单明细,一个图书报损单明细对应一个图书,图书和图书报损单明细是一对多联系。

      9.一个读者对应多个罚款交费单,一个罚款交罚单对应一个读者,读者和罚款交费单是一对多联系。

     10.一个职工对应多个图书入库单,一个图书入库单对应一个职工,职工和图书入库单是一对多联系。

     11.一个职工对应多个图书报损单,一个图书报损单对应一个职工,职工和图书报损单是一对多联系。

     12.一个职工对应多个罚款交费单,一个罚款交费单对应一个职工,职工和罚款交费单是一对多联系。

     13.一个读者对应多个图书,一个图书对应多个读者,读者和图书之间是多对多联系。

2.3 整体简化E-R图
 

第3章 数据库逻辑结构设计
3.1 E-R图向关系模式转换的原则
1. 一个实体型转换为一个关系模式。

关系的属性:实体型的属性

关系的码:实体型的码

2.一个1:1联系可以转换为一个独立的关系模式,也可以与任何一端对应的关系模式合并。

3.一个1:n联系可以转换为一个独立的关系模式,也可以与n端对应的关系模式 合并。

4.一个m:n联系转换为一个关系模式。

5.三个或三个以上实体间的一个多元联系可以转换为一个关系模式。

6.具有相同码的关系模式可合并。

目的:减少系统中关系个数

7.同一实体集的实体之间的联系即自联系,也可以按1:1,1:n和m:n三种情况分别处理。

3.2各个表的逻辑结构
 

表3.1  出版社表

列  名

数据类型

长 度

主  键

非空

备注

出版社编号

Int

Yes

出版社名称

Varchar

50

Yes

出版社地址

Varchar

50

Yes

           

表3.2  图书表

列  名

数据类型

长 度

主  键

非空

备注

图书编号

varchar

20

Yes

出版社编号

Int

Yes

外码,参照出版表出版社编号

图书类型编号

char

1

Yes

外码,参照图书类型表,图书类型编号

书名

varchar

50

Yes

作者

varchar

20

Yes

价格

Numeric(8,2)

Yes

页码

Int

Yes

库存总量

Int

Yes

现存量

Int

Yes

入库时间

Datetime

借出次数

Int

Yes

          

 表3.3  图书类型表

列  名

数据类型

长 度

主  键

非空

备注

图书类型编号

Char

1

Yes

Yes

图书类型名

varchar

50

Yes

书库号

int

外码,参照书库表的书库号

表3.4  读者表

列  名

数据类型

长 度

主  键

非空

备注

证书编号

int

Yes

Yes

读者类型编号

Char

10

外码,参照读者类型表的读者类型编号

姓名

varchar

50

Yes

性别

Char

10

Yes

只能为“男”、或“女”

出生日期

Datetime

Yes

身份证编号

char

18

Yes

必须是18位  

图书借阅次数

int

是否挂失

int

0未挂失

1已挂失

已借册数

int

未交罚款金额

Numeric(8,2)

表3.5  读者类型表

列  名

数据类型

长 度

主  键

非空

备注

读者类型编号

Char

10

Yes

Yes

读者类型名

vachar

20

Yes

可借阅册数

Int

Yes

有效范围是20---60

借期天数

int

Yes

有效范围是90---120

可续借天数

int

Yes

有效范围是10---60

           

表3.6  书库表

列  名

数据类型

长 度

主  键

非空

备注

书库号

int

Yes

Yes

书库名

varchat

50

Yes

表3.7 职工表

列  名

数据类型

长 度

主  键

非空

备注

职工编号

int

Yes

Yes

职工姓名

varchar

50

Yes

性别

Char

10

Yes

只能为“男”、或“女”

出生日期

Datetime

Yes

文化程度

varchar

20

Yes

表3.8 罚款交费单表

列  名

数据类型

长 度

主  键

非空

备注

交费单号

int

Yes

Yes

借书证编号

int

Yes

外码,参照读者表证书编号

日期

Datetime

Yes

金额

Numeric(8,2)

Yes

表3.9 图书入库单表

列  名

数据类型

长 度

主  键

非空

备注

入库编号

int

Yes

Yes

入库日期

Datetime

Yes

经手职工编号

int

外码,参照职工表的职工编号

是否入库

int

0已入库

1未入库

表3.10 图书入库单明细表

列  名

数据类型

长 度

主  键

非空

备注

图书入库单编号

int

Yes

报损单编号和图书编号一起作为主码

Yes

外码,参照图书入库单表的图书入库编号

图书编号

varchar

20

Yes

外码,参照图书表的图书编号

数量

int

Yes

表3.11 图书报损单表

列  名

数据类型

长 度

主  键

非空

备注

报损单编号

int

Yes

Yes

报损日期

Datetime

Yes

经手人编号

int

外码,参照职工表的职工编号

表3.12 图书报损单明细

列  名

数据类型

长 度

主  键

非空

备注

图书报损单编号

int

Yes

报损单编号和图书编号一起作为主码

Yes

外码,参照图书报损单表的报损单编号

图书编号

varchar

20

Yes

外码,参照图书表的图书编号

数量

int

Yes

报损原因

Varchar

100

Yes

表3.13借阅表

列  名

数据类型

长 度

主  键

非空

备注

借书证编号

int

Yes

借书证编号和图书编号一起作为主码

Yes

外码,参照读者表的证书编号

图书编号

varchar

20

Yes

外码,参照图书表的图书编号

借书日期

Datetime

Yes

还书日期

Datetime

还书日期>=借书日期

罚款金额

Numeric(8,2)

是否续借

int

0未续借

1已续借

3.3 视图结构
 

3.3.1  入库单视图

列  名

来源表

入库单编号

图书入库单表

入库日期

图书入库单表

经手人姓名

职工表

是否已入库

图书入库单表

图书编号

图书入库单明细表

书名

图书表

出版社名

出版社表

入库数量

图书入库单明细表

         

表3.3.2  报损单视图

列  名

来源表

报损单编号

图书报损单表

报损日期

图书报损单表

经手人姓名

职工表

图书编号

图书报损单明细表

书名

图书表

出版社名

出版社表

报损数量

图书报损单明细表

报损原因

图书报损单明细表

         

表3.3.3  读者未还借书视图

列  名

来源表

借书证编号

借阅表

读者姓名

读者表

未还书编号

借阅表

未还书名

图书表

出版社名

出版社表

借书日期

借阅表

可借期天数

读者类型表

罚款金额

借阅表

         

表3.3.4  图书分类库存视图

列  名

来源表

 图书类型编号

图书类型表

 图书类型名

图书类型表

 库存册数合计

图书表

 库存金额合计

图书表

表3.3.5   借出次数前100图书视图

列  名

来源表

 图书编号

图书表

 书名

图书表

 借出次数

图书表

       
 

第4章 数据库物理结构设计
4.1索引的设计原则
  (1)如果一个(或一组)属性经常在查询条件中出现,则考虑早这个(或这组)属性建立索引。

(2)如果一个属性经常作为最大值和最小值等聚集函数的参数,则考虑这个属性上建立索引。

(3)如果一个(或一组)属性经常在连接操作的连接条件中出现,则考虑在这个(或这组)属性上建立索引。

4.2 索引结构设计 
                                                                                                                              表4.1  索引结构表

表名

索引名

索引列

备注(索引的设计理由)

图书

书名索引

书名

经常查询的列

图书

出版社编号索引

出版编社号

经常连接的列

图书

图书类型索引

图书类型编号

经常连接的列

图书

作者索引

作者

经常查询的列

图书类型

书库号索引

书库号

经常连接的列

读者

姓名索引

姓名

经常查询的列

读者

图书借阅次数索引

图书借阅次数

聚集函数的参数

读者

已借册数索引

已借册数

聚集函数的参数

读者

未交罚款金额索引

未交罚款金额

聚集函数的参数

职工

姓名索引

姓名

经常查询的列

罚款交费单

借书证编号索引

借书证编号

经常连接的列

图书入库单

经手职工编号索引

经手职工编号

经常连接的列

图书入库单明细

图书入库单编号索引

图书入库单编号

经常连接的列

图书入库单明细

图书编号索引

图书编号

经常连接的列

图书报损单

经手职工编号索引

经手职工编号

经常连接的列

图书报损单明细

图书报损单编号索引

图书报损单编号

经常连接的列

图书报损单明细

图书编号索引

图书编号

经常连接的列

借阅

借书证编号索引

借书证编号

经常连接的列

借阅

图书编号索引

图书编号

经常连接的列

   

第5章 数据库实施
5.1 建表语句

CREATE TABLE 出版社
 (
 出版社编号 INT PRIMARY KEY,
 出版社名称 VARCHAR(50) NOT NULL,
 出版社地址 VARCHAR(50)
 );

 CREATE TABLE 书库
 (
 书库号 INT PRIMARY KEY,
 书库名 VARCHAR(50) NOT NULL
 );

 CREATE TABLE 图书类型
 (
 图书类型编号 CHAR(1) PRIMARY KEY,
 图书类型名 VARCHAR(50) NOT NULL,
 书库号 INT ,
 FOREIGN KEY(书库号) REFERENCES 书库(书库号)
 );

 CREATE TABLE 图书
 (
 图书编号 VARCHAR(20) PRIMARY KEY,
 出版社编号 INT NOT NULL,
 图书类型编号 CHAR(1) ,
 书名 VARCHAR(50) NOT NULL,
 作者 VARCHAR(20) NOT NULL,
 价格 NUMERIC(8,2) NOT NULL,
 页码 INT NOT NULL,
 库存总量 INT NOT NULL,
 现存量 INT NOT NULL,
 入库时间 DATETIME ,
 借出次数 INT NOT NULL,
 FOREIGN KEY(出版社编号) REFERENCES 出版社(出版社编号),
 FOREIGN KEY(图书类型编号) REFERENCES 图书类型(图书类型编号)
 );

 CREATE TABLE 读者类型
 (
 读者类型编号 CHAR(10) PRIMARY KEY,
 读者类型名 VARCHAR(20) NOT NULL,
 可借阅册数 INT CHECK(可借阅册数>=20 AND 可借阅册数<=60),
 借期天数 INT  CHECK(借期天数>=90 AND 借期天数<=120),
 可续借天数 INT  CHECK(可续借天数>=10 AND 可续借天数<=60)
 )

 CREATE TABLE 读者
 (
 证书编号 INT PRIMARY KEY,
 读者类型编号 CHAR(10),
 姓名 VARCHAR(50) NOT NULL,
 性别 CHAR(10) CHECK (性别 IN ('男','女')),
 出生日期 DATETIME NOT NULL,
 身份证编号 CHAR(18) CHECK(LEN(TRIM(身份证编号))=18),
 图书借阅次数 INT,
 是否挂失 INT,
 已借册数 INT,
 未交罚款金额 NUMERIC(8,2),
 FOREIGN KEY(读者类型编号) REFERENCES 读者类型 (读者类型编号)
 )

 CREATE TABLE 职工
 (
 职工编号 INT  PRIMARY KEY,
 职工姓名 VARCHAR(50) NOT NULL,
 性别 CHAR(10) CHECK (性别  IN ('男','女')),
 出生日期 DATETIME NOT NULL,
 文化程度 VARCHAR(20) NOT NULL
 )

 CREATE TABLE 罚款交费单
 (
 交费单号 INT PRIMARY KEY,
 借书证编号 INT ,
 日期 DATETIME NOT NULL,
 金额 NUMERIC(8,2) NOT NULL,
 FOREIGN KEY(借书证编号) REFERENCES 读者(证书编号)
  )


  CREATE TABLE 图书入库单
  (
  入库单编号 INT PRIMARY KEY,
  入库日期 DATETIME NOT NULL,
  经手人编号 INT,
  是否入库 INT,
  FOREIGN KEY(经手人编号) REFERENCES 职工(职工编号)
  )

  CREATE TABLE 图书入库单明细
  (
  入库单编号 INT,
  图书编号 VARCHAR(20),
  数量 INT NOT NULL,
  PRIMARY KEY(入库单编号,图书编号),
  FOREIGN KEY(入库单编号) REFERENCES 图书入库单(入库单编号),
  FOREIGN KEY(图书编号) REFERENCES 图书(图书编号)
  )

  CREATE TABLE 图书报损单
  (
  报损单编号 INT PRIMARY KEY,
  报损日期 DATETIME NOT NULL,
  经手人编号 INT,
  FOREIGN KEY(经手人编号) REFERENCES 职工(职工编号)
  )

  CREATE TABLE 图书报损单明细
  (
  报损单编号 INT,
  图书编号 VARCHAR(20),
  数量 INT NOT NULL,
  报损原因 VARCHAR(100) NOT NULL,
  PRIMARY KEY(报损单编号,图书编号),
  FOREIGN KEY(报损单编号) REFERENCES 图书报损单(报损单编号),
  FOREIGN KEY(图书编号) REFERENCES 图书(图书编号)
  )

  CREATE TABLE 借阅
  (
  借书证编号 INT ,
  图书编号 VARCHAR(20),
  借书日期 DATETIME NOT NULL,
  还书日期 DATETIME,
  罚款金额 NUMERIC(8,2),
  是否续借 INT,
  CHECK (借书日期>=还书日期),
  PRIMARY KEY(借书证编号,图书编号),
  FOREIGN KEY(借书证编号) REFERENCES 读者(证书编号),
  FOREIGN KEY(图书编号) REFERENCES 图书(图书编号)
  )

5.2 建视图语句

CREATE VIEW 入库单(入库单编号,入库日期,经手人姓名,是否已入库,图书编号,书名,出版社名,入库数量)
 AS
 SELECT 图书入库单.入库单编号,图书入库单.入库日期,职工.职工姓名,图书入库单.是否入库,图书入库单明细.图书编号,图书.书名,出版社.出版社名称,图书入库单明细.数量
 FROM 图书入库单,图书入库单明细,职工,图书,出版社
 WHERE 图书入库单明细.入库单编号=图书入库单.入库单编号 AND 图书入库单明细.图书编号=图书.图书编号 AND 图书入库单.经手人编号=职工.职工编号 AND 图书.出版社编号=出版社.出版社编号

CREATE VIEW 报损单(报损单编号,报损日期,经手人姓名,图书编号,书名,出版社名,报损数量,报损原因)
 AS
 SELECT 图书报损单.报损单编号,图书报损单.报损日期,职工.职工姓名,图书报损单明细.图书编号,图书.书名,出版社.出版社名称,图书报损单明细.数量,图书报损单明细.报损原因
 FROM  图书报损单,职工,图书报损单明细,图书,出版社
 WHERE 图书报损单明细.报损单编号=图书报损单.报损单编号 AND 图书报损单明细.图书编号=图书.图书编号 AND 图书报损单.经手人编号=职工.职工编号 AND 图书.出版社编号=出版社.出版社编号

CREATE VIEW 读者未还借书(借书证编号,读者姓名,未还书编号,未还书名,出版社名,借书日期,可借期天数,罚款金额)
 AS
 SELECT 借阅.借书证编号,读者.姓名,借阅.图书编号,图书.书名,出版社.出版社名称,借阅.借书日期,读者类型.可续借天数,借阅.罚款金额
 FROM  借阅,读者,图书,出版社,读者类型
 WHERE 借阅.借书证编号=读者.证书编号 AND 借阅.图书编号=图书.图书编号 AND  图书.出版社编号=出版社.出版社编号 AND 读者.读者类型编号=读者类型.读者类型编号

CREATE VIEW 图书分类库存(图书类型编号,图书类型名,库存册数合计,库存金额合计)
 AS
 SELECT 图书类型.图书类型编号,图书类型.图书类型名,sum(图书.库存总量),sum(图书.价格*图书.库存总量)
 FROM  图书,图书类型
 WHERE 图书类型.图书类型编号=图书.图书类型编号
 GROUP BY 图书类型.图书类型编号,图书类型.图书类型名

CREATE VIEW 借出次数前100图书(图书编号,书名,借出次数)
 AS
 SELECT TOP(100) 图书编号,书名,借出次数
 FROM  图书
 ORDER BY 借出次数 DESC

5.3建索引语句

  CREATE INDEX 书名索引 ON 图书(书名);
  CREATE INDEX 出版社编号索引 ON 图书(出版社编号);
  CREATE INDEX 图书类型编号索引 ON 图书(图书类型编号);
  CREATE INDEX 作者索引 ON 图书(作者);
  CREATE INDEX 书库号索引 ON 图书类型(书库号);
  CREATE INDEX 姓名索引 ON 读者(姓名);
  CREATE INDEX 图书借阅次数索引 ON 读者(图书借阅次数);
  CREATE INDEX 已借册数索引 ON 读者(已借册数);
  CREATE INDEX 未交罚款金额索引 ON 读者(未交罚款金额);
  CREATE INDEX 职工姓名索引 ON 职工(职工姓名);
  CREATE INDEX 借书证编号索引 ON 罚款交费单(借书证编号);
  CREATE INDEX 经手职工编号索引 ON 图书入库单(经手人编号);
  CREATE INDEX 图书入库单编号索引 ON 图书入库单明细(入库单编号);
  CREATE INDEX 图书编号索引 ON 图书入库单明细(图书编号);
  CREATE INDEX 经手职工编号索引 ON 图书报损单(经手人编号);
  CREATE INDEX 图书报损单编号索引 ON 图书报损单明细(报损单编号);
  CREATE INDEX 图书编号索引 ON 图书报损单明细(图书编号);
  CREATE INDEX 借书证编号索引 ON 借阅(借书证编号);
  CREATE INDEX 图书编号索引 ON 借阅(图书编号);

5.4存储过程
   每个存储过程的功能说明和建立语句


  INSERT INTO 书库 VALUES(2,'理工库' );
  INSERT INTO 图书类型 VALUES('T','工业技术', 2);
  INSERT INTO 出版社 VALUES (1 ,'清华大学出版社','北京');
  INSERT INTO 图书(图书类型编号, 出版社编号, 图书编号,书名,作者,价格,页码,现存量,库存总量,入库时间,借出次数) VALUES ( 'T', 1, '101',  '数据库系统原理' , '王珊' , '20' , '400', 0,0,null,0);
  INSERT INTO 图书(图书类型编号, 出版社编号, 图书编号,书名,作者,价格,页码,现存量,库存总量,入库时间,借出次数) VALUES ( 'T', 1, '102',  'C程序设计' , '谭浩强 ', '18 ' , '300' , 0,0,null,0);
  INSERT INTO 图书(图书类型编号, 出版社编号, 图书编号,书名,作者,价格,页码,现存量,库存总量,入库时间,借出次数) VALUES ( 'T', 1, '103',  '计算机组成原理' , '张兵' , '20' , '400' , 0,0,null,0);
  INSERT INTO 职工 VALUES(10001,'王小伟','男', 1995-3-7,'本科');
  INSERT INTO 图书入库单(入库单编号,入库日期,经手人编号,是否入库) VALUES(100,'7-1-2018' ,'10001',0);
  INSERT INTO 图书入库单明细(入库单编号,图书编号,数量) VALUES(100,101,75);
  INSERT INTO 图书入库单明细(入库单编号,图书编号,数量) VALUES(100,102,75);
  INSERT INTO 图书入库单明细(入库单编号,图书编号,数量) VALUES(100,103,75);

存储过程


GO
  CREATE  PROCEDURE  P1  
  @入库单号   INT
AS
DECLARE @图书编号 INT, @数量 INT ,@是否已入库 INT ,@入库日期 DATETIME
DECLARE C1 CURSOR FOR       
       SELECT 图书编号,数量 FROM 图书入库单明细 WHERE 入库单编号=@入库单号
SELECT @是否已入库=是否入库, @入库日期=入库日期
FROM 图书入库单
WHERE 入库单编号=@入库单号
IF @是否已入库=0
BEGIN

OPEN C1
BEGIN TRANSACTION  /* 处理之前  开始事务(要么全做,要么全不做) */
/* 处理 */
WHILE 1=1
BEGIN
  FETCH NEXT FROM C1 INTO  @图书编号, @数量
  IF @@fetch_status<>0  
         BREAK 
  UPDATE 图书/*修改图书表*/
  SET 库存总量=库存总量+@数量,现存量=现存量+@数量,入库时间=@入库日期
  WHERE 图书编号=@图书编号
END   
CLOSE C1
DEALLOCATE C1
UPDATE 图书入库单/*修改图书入库单表*/
SET 是否入库=1
WHERE 入库单编号=@入库单号
COMMIT    /* 一个订单的订单明细全部处理完成  */
END
GO

执行存储过程

EXEC P1 100
 

SELECT *
FROM 图书入库单明细


 

select *
from 图书


 

5.5触发器
   每个触发器的功能说明和建立语句

  

1.编写图书入库单明细表的DELETE触发器, 如已经入库(对应入库单的<是否已入库> 为1), 报错’已入库不能删除!’,回滚事务

(在触发器中执行ROLLBACK TRANSACTION, 回滚(撤销)引起触发器DELETE的语句)


GO
CREATE TRIGGER trig_delete_tsrkdmx
ON 图书入库单明细
FOR DELETE AS
  DECLARE @是否入库 INT,@入库单编号 INT
  SET @入库单编号 = (SELECT TOP 1 入库单编号 FROM deleted)
  SET @是否入库 = (SELECT 是否入库 FROM 图书入库单 WHERE 入库单编号=@入库单编号)
  IF @是否入库=1
  BEGIN
     RAISERROR('已入库不能删除!',16,1)
     ROLLBACK TRANSACTION
     END
GO 

测试:

删除入库明细单中入库单号为100的行

触发器报错, 删除失败,截图

delete
from 图书入库单明细
where 入库单编号=100
 

2 编写图书入库单明细表的UPDATE触发器, 如已经入库(对应入库单<是否已入库> 为1),报错’已入库不能修改’,回滚事务


GO
CREATE TRIGGER trig_update_tsrkdmx
ON 图书入库单明细
FOR UPDATE AS
  DECLARE @是否入库 INT,@入库单编号 INT
  SET @入库单编号 = (SELECT TOP 1 入库单编号 FROM deleted)
  SET @是否入库 = (SELECT 是否入库 FROM 图书入库单 WHERE 入库单编号=@入库单编号)
  IF @是否入库=1
  BEGIN
     RAISERROR('已入库不能修改!',16,1)
     ROLLBACK TRANSACTION
     END
GO 

测试:

UPDATE入库明细单中入库单号为100的行

触发器报错, update失败

update 图书入库单明细
set 数量=110
where 入库单编号=100
 

3读者借书时, 要插入借阅行

编写触发器,当插入借阅时

如读者已借够可借册数,

不准借了(报错, 回滚事务)

如或读者有未交罚款>100

不准借了(报错, 回滚事务)

否则

{

将读者已借册数加1, 图书借阅次数加1,将图书的借出次数加1,现存量减1

}


GO
CREATE TRIGGER trig_insert_jieyue
ON 借阅
FOR INSERT AS
  DECLARE @借书证编号 INT,@已借册数 INT,@可借册数 INT,@读者类型编号 CHAR(10),@未交罚款金额 NUMERIC(8,2),@图书编号 VARCHAR(20)
  SET @借书证编号 = (SELECT TOP 1 借书证编号 FROM inserted) 
  SET @图书编号 = (SELECT TOP 1 图书编号 FROM inserted)
  SET @已借册数 = (SELECT 已借册数 FROM 读者 WHERE 证书编号=@借书证编号)
  SET @读者类型编号 = (SELECT 读者类型编号 FROM 读者 WHERE 证书编号=@借书证编号)
  SET @未交罚款金额 = (SELECT 未交罚款金额 FROM 读者 WHERE 证书编号=@借书证编号)
  SET @可借册数 =(SELECT 可借阅册数 FROM 读者类型 WHERE 读者类型编号=@读者类型编号)
  IF @已借册数> @可借册数
  BEGIN
     RAISERROR('读者已借够可借册数!',16,1)
     ROLLBACK TRANSACTION
  END
  ELSE IF @未交罚款金额>100
  BEGIN
     RAISERROR('读者有未交罚款!',16,1)
     ROLLBACK TRANSACTION
  END
  ELSE
   BEGIN
    UPDATE 读者
    SET 图书借阅次数=图书借阅次数+1
    WHERE 证书编号= @借书证编号
    UPDATE 图书
    SET 借出次数=借出次数+1,现存量=现存量-1
    WHERE 图书编号= @图书编号
  END
GO 

测试:

自行设计测试数据

INSERT INTO 读者类型(读者类型编号,读者类型名,可借阅册数,借期天数,可续借天数) VALUES('10000','本科生',30,90,10  );
INSERT INTO 读者(证书编号,姓名,读者类型编号,性别,出生日期,身份证编号,图书借阅次数,是否挂失,已借册数,未交罚款金额)
VALUES(10,'王陆','10000','男','1999-5-6','370683199703786815',10,0,20,110);
INSERT INTO 借阅(借书证编号, 图书编号,借书日期,还书日期,是否续借,罚款金额) VALUES(10,'101','2019-6-21',NULL,0,0);
 

4读者还书时, 要修改借阅表,设置还书日期。

编写触发器,当修改借阅时(一次只修改一行,不考虑修改多行的情况,不用游标)

如果还书日期原来为空值,新值不是空值(这表明是还书操作)

     将读者的已借册数减1, 将图书的现存量加1

如果罚款金额原来为空值,新值不是空值(这表明是有罚款)

     将读者的未交罚款增加

如果罚款金额原来不是空值,新值不是空值(这表明是罚款修改了)

     将读者的未交罚款调整 ( 减旧罚款, 加新罚款)


GO
CREATE TRIGGER trig_update_jieyue
ON 借阅
FOR UPDATE AS
  DECLARE @原还书日期 DATETIME,@新还书日期 DATETIME,@原罚款金额 NUMERIC(8,2),@新罚款金额 NUMERIC(8,2),@借书证编号 INT,@已借册数 INT,@图书编号 VARCHAR(20)
  SET @原还书日期 = (SELECT TOP 1 还书日期 FROM deleted) 
  SET @新还书日期 = (SELECT TOP 1 还书日期 FROM inserted) 
  SET @原罚款金额 = (SELECT TOP 1 罚款金额 FROM deleted) 
  SET @新罚款金额 = (SELECT TOP 1 罚款金额 FROM inserted)
  SET @借书证编号 = (SELECT TOP 1 借书证编号 FROM deleted) 
  SET @图书编号 = (SELECT TOP 1 图书编号 FROM deleted)
  SET @已借册数 = (SELECT 已借册数 FROM 读者 WHERE 证书编号=@借书证编号)
  IF @原还书日期 IS NULL AND @新还书日期 IS NOT NULL--还书操作
  BEGIN
    UPDATE 读者
    SET 图书借阅次数=图书借阅次数-1
    WHERE 证书编号= @借书证编号
    UPDATE 图书
    SET 现存量=现存量+1
    WHERE 图书编号= @图书编号
  END
  IF @原罚款金额 IS NULL AND @新罚款金额 IS NOT NULL--未交罚款增加
  BEGIN
    UPDATE 读者
    SET 未交罚款金额=@新罚款金额
    WHERE 证书编号= @借书证编号
  END
  IF @原罚款金额 IS NOT NULL AND @新罚款金额 IS NOT NULL--未交罚款修改
  BEGIN
  UPDATE 读者
    SET 未交罚款金额=未交罚款金额+@新罚款金额
    WHERE 证书编号= @借书证编号
  END
GO

测试:

自行设计测试数据


INSERT INTO 读者类型(读者类型编号,读者类型名,可借阅册数,借期天数,可续借天数) VALUES('10000','本科生',30,90,10  );
INSERT INTO 读者(证书编号,姓名,读者类型编号,性别,出生日期,身份证编号,图书借阅次数,是否挂失,已借册数,未交罚款金额)
VALUES(10,'王陆','10000','男','1999-5-6','370683199703786815',10,0,20,30);
INSERT INTO 借阅(借书证编号, 图书编号,借书日期,还书日期,是否续借,罚款金额) VALUES(10,'101','2019-6-21',NULL,0,0);
SELECT *
FROM 借阅
 UPDATE 借阅
 SET 还书日期='2019-6-21'
 WHERE 借书证编号=10
 UPDATE 借阅
 SET 罚款金额=罚款金额+5
 WHERE 借书证编号=10

 SELECT *
 FROM 借阅

 SELECT *
 FROM 读者
 
 SELECT *
 FROM 图书

5 读者交罚款时, 要插入罚款交费单

编写触发器,当插入罚款交费单

将读者的未交罚款减少


GO
CREATE TRIGGER trig_insert_fakuan
ON 罚款交费单
FOR INSERT AS
  DECLARE @借书证编号 INT,@金额 NUMERIC(8,2) 
  SET @借书证编号 = (SELECT TOP 1 借书证编号 FROM inserted) 
  SET @金额 = (SELECT TOP 1 金额 FROM inserted)
  IF @金额 IS NOT NULL
  BEGIN
    UPDATE 读者
    SET 未交罚款金额=未交罚款金额-@金额
    WHERE 证书编号= @借书证编号
  END
GO

测试:

自行设计测试数据


INSERT INTO 读者类型(读者类型编号,读者类型名,可借阅册数,借期天数,可续借天数) VALUES('10000','本科生',30,90,10  );
INSERT INTO 读者(证书编号,姓名,读者类型编号,性别,出生日期,身份证编号,图书借阅次数,是否挂失,已借册数,未交罚款金额)
VALUES(10,'王陆','10000','男','1999-5-6','370683199703786815',10,0,20,100);
INSERT INTO 借阅(借书证编号, 图书编号,借书日期,还书日期,是否续借,罚款金额) VALUES(10,'101','2019-6-21',NULL,0,0);
INSERT INTO 罚款交费单(交费单号,日期,职工编号,金额,借书证编号)  VALUES(1,'2019-6-22',10001,100,10);
select *
from 读者

6  编写触发器,借书表不允许DELETE操作


GO
CREATE TRIGGER trig_delete_jieyue
ON 借阅
FOR DELETE AS
 RAISERROR('借书表不允许DELETE操作',16,1)
 ROLLBACK TRANSACTION
GO 

测试:

自行设计测试数据

DELETE 
FROM 借阅
 

7  编写报损单触发器


GO
CREATE TRIGGER trig_insert_baosun
ON 图书报损单明细
FOR INSERT AS
  DECLARE @数量 INT,@图书编号 VARCHAR(20)
  SET @数量 = (SELECT TOP 1 数量 FROM inserted) 
  SET @图书编号 = (SELECT TOP 1 图书编号 FROM inserted)
    UPDATE 图书
    SET 库存总量=库存总量-@数量,现存量=现存量-@数量
    WHERE 图书编号= @图书编号 
GO

第6章 测试数据
6.1完整的测试数据

/*在出版社表插入5行数据 
*/
 INSERT INTO 出版社 VALUES (1 ,'清华大学出版社','北京');
 INSERT INTO 出版社 VALUES (2 ,'高等教育出版社','北京');
 INSERT INTO 出版社 VALUES (3 ,'天津大学出版社','天津');
 INSERT INTO 出版社 VALUES (4 ,'复旦大学出版社','上海');
 INSERT INTO 出版社 VALUES (5 ,'山东大学出版社','济南');
/*在书库表插入4行数据*/
 INSERT INTO 书库 VALUES(1,'文史库' ); 
 INSERT INTO 书库 VALUES(2,'理工库' );
 INSERT INTO 书库 VALUES(3,'经管库' ); 
 INSERT INTO 书库 VALUES(4,'政法库' ); 

/*在图书类型表插入5行数据,注意图书类型编号为字符型   
*/
 INSERT INTO 图书类型 VALUES('T','工业技术', 2);
 INSERT INTO 图书类型 VALUES('A','马克思,列,毛,邓', 4);
 INSERT INTO 图书类型 VALUES('K','历史地理', 1);
 INSERT INTO 图书类型 VALUES('F','经济', 3);
 INSERT INTO 图书类型 VALUES('I','文学', 1);

/*在图书表插入20行数据 */
INSERT INTO 图书(图书类型编号, 出版社编号, 图书编号,书名,作者,价格,页码,现存量,库存总量,入库时间,借出次数) 
VALUES ( 'T', 1, '101',  '数据库系统原理' , '王珊' , '20' , '400', 100,100,'6-10-2019',0);
INSERT INTO 图书(图书类型编号, 出版社编号, 图书编号,书名,作者,价格,页码,现存量,库存总量,入库时间,借出次数) 
VALUES ( 'T', 1, '102',  'C程序设计' , '谭浩强 ', '18 ' , '300' ,100,100,'6-10-2019',0);
INSERT INTO 图书(图书类型编号, 出版社编号, 图书编号,书名,作者,价格,页码,现存量,库存总量,入库时间,借出次数) 
VALUES ( 'T', 1, '103',  '计算机组成原理' , '张兵' , '20' , '400' ,100,100,'6-10-2019',0);
INSERT INTO 图书(图书类型编号, 出版社编号, 图书编号,书名,作者,价格,页码,现存量,库存总量,入库时间,借出次数) 
VALUES ( 'A', 2, '104',  '毛思想和中特社' , '高英王洋' , '20' , '400' ,100,100,'6-19-2019',0);
INSERT INTO 图书(图书类型编号, 出版社编号, 图书编号,书名,作者,价格,页码,现存量,库存总量,入库时间,借出次数) 
VALUES ( 'F ',3, '105',  '经济学导论' , '罗丽英' , '20' , '400' ,100,100,'6-19-2019',0);
INSERT INTO 图书(图书类型编号, 出版社编号, 图书编号,书名,作者,价格,页码,现存量,库存总量,入库时间,借出次数) 
VALUES ( 'K', 4, '106',  '中国近代史' , '张鸣' , '40' , '400' ,100,100,'6-19-2019',0);
INSERT INTO 图书(图书类型编号, 出版社编号, 图书编号,书名,作者,价格,页码,现存量,库存总量,入库时间,借出次数) 
VALUES ( 'I', 5, '107',  '鲁迅文集' , '鲁迅' , '30' , '400' ,100,100,'6-20-2019',0);

/*在读者类型表插入4行数据 

*/
INSERT INTO 读者类型(读者类型编号,读者类型名,可借阅册数,借期天数,可续借天数) VALUES('bk01','本科生',30,90,10  );
INSERT INTO 读者类型(读者类型编号,读者类型名,可借阅册数,借期天数,可续借天数) VALUES('yj01','研究生',40,100,10  );
INSERT INTO 读者类型(读者类型编号,读者类型名,可借阅册数,借期天数,可续借天数) VALUES('js01','讲师',50,110,20  );
INSERT INTO 读者类型(读者类型编号,读者类型名,可借阅册数,借期天数,可续借天数) VALUES('js02','教授',60,120,30  );
/*在读者表插入10行数据*/

INSERT INTO 读者(证书编号,姓名,读者类型编号,性别,出生日期,身份证编号,图书借阅次数,是否挂失,已借册数,未交罚款金额)
VALUES(10,'王陆','bk01','男','1999-5-6','370683199905066815',10,0,20,10);

INSERT INTO 读者(证书编号,姓名,读者类型编号,性别,出生日期,身份证编号,图书借阅次数,是否挂失,已借册数,未交罚款金额)
VALUES(11,'王舞','bk01','女','1998-5-16','370683199805166816',10,0,20,0);

INSERT INTO 读者(证书编号,姓名,读者类型编号,性别,出生日期,身份证编号,图书借阅次数,是否挂失,已借册数,未交罚款金额)
VALUES(12,'陆飘','yj01','女','1995-4-16','370683199504166816',10,0,20,20);

INSERT INTO 读者(证书编号,姓名,读者类型编号,性别,出生日期,身份证编号,图书借阅次数,是否挂失,已借册数,未交罚款金额)
VALUES(13,'张山','js01','男','1988-5-16','370683198805166816',10,0,20,30);

INSERT INTO 读者(证书编号,姓名,读者类型编号,性别,出生日期,身份证编号,图书借阅次数,是否挂失,已借册数,未交罚款金额)
VALUES(14,'刘勇','js02','男','1977-5-17','370683199805176816',10,0,20,0);

INSERT INTO 读者(证书编号,姓名,读者类型编号,性别,出生日期,身份证编号,图书借阅次数,是否挂失,已借册数,未交罚款金额)
VALUES(15,'孔燕','js02','女','1978-5-16','370683197807166816',10,0,20,0);

/*在职工插入5行数据*/
 INSERT INTO 职工 VALUES(10001,'王小伟','男', '1995-3-7','本科');
 INSERT INTO 职工 VALUES(10002,'张三','男', '1996-7-8','本科');
 INSERT INTO 职工 VALUES(10003,'李四','男', '1994-5-3','本科');
 INSERT INTO 职工 VALUES(10004,'王五','男', '1995-4-23','本科');
 INSERT INTO 职工 VALUES(10005,'小六','男', '1997-3-17','本科');
/*在图书入库单表插入5行数据,是否已入库的值是0
     注意,日期格式:  ‘月-日-年’, 例如 ’6-20-2016’
*/
INSERT INTO 图书入库单(入库单编号,入库日期,经手人编号,是否入库) 
VALUES(100,'6-10-2019' ,10001,0);
INSERT INTO 图书入库单(入库单编号,入库日期,经手人编号,是否入库) 
VALUES(101,'6-19-2019' ,10002,0);
INSERT INTO 图书入库单(入库单编号,入库日期,经手人编号,是否入库) 
VALUES(102,'6-20-2019' ,10003,0);
/*对应每个入库单,各输入3个明细数据  
*/
INSERT INTO 图书入库单明细(入库单编号,图书编号,数量) VALUES(100,101,100);
INSERT INTO 图书入库单明细(入库单编号,图书编号,数量) VALUES(100,102,100);
INSERT INTO 图书入库单明细(入库单编号,图书编号,数量) VALUES(100,103,100);

INSERT INTO 图书入库单明细(入库单编号,图书编号,数量) VALUES(101,104,100);
INSERT INTO 图书入库单明细(入库单编号,图书编号,数量) VALUES(101,105,100);
INSERT INTO 图书入库单明细(入库单编号,图书编号,数量) VALUES(101,106,100);

INSERT INTO 图书入库单明细(入库单编号,图书编号,数量) VALUES(102,107,100);

/*在图书报损单表插入2行数据,报损单号为5,日期为2016.6.20 
*/
INSERT INTO 图书报损单(报损单编号,报损日期,经手人编号) 
VALUES(5,'6-20-2019' ,10004);
INSERT INTO 图书报损单(报损单编号,报损日期,经手人编号) 
VALUES(6,'6-20-2019' ,10005);
/*对应每个入库单,各输入3个明细数据  
*/

INSERT INTO 图书报损单明细(报损单编号,图书编号,数量,报损原因) VALUES(5,101,1,'图书丢失');
INSERT INTO 图书报损单明细(报损单编号,图书编号,数量,报损原因) VALUES(5,102,1,'图书丢失');
INSERT INTO 图书报损单明细(报损单编号,图书编号,数量,报损原因) VALUES(5,103,1,'图书丢失');
INSERT INTO 图书报损单明细(报损单编号,图书编号,数量,报损原因) VALUES(6,104,1,'图书丢失');
INSERT INTO 图书报损单明细(报损单编号,图书编号,数量,报损原因) VALUES(6,105,1,'图书丢失');
INSERT INTO 图书报损单明细(报损单编号,图书编号,数量,报损原因) VALUES(6,106,1,'图书丢失');
/*在借书表插入10行数据 */

INSERT INTO 借阅(借书证编号, 图书编号,借书日期,还书日期,是否续借,罚款金额) VALUES(10,'101','2019-6-11',NULL,0,0);
INSERT INTO 借阅(借书证编号, 图书编号,借书日期,还书日期,是否续借,罚款金额) VALUES(10,'102','2019-6-11',NULL,0,0);
INSERT INTO 借阅(借书证编号, 图书编号,借书日期,还书日期,是否续借,罚款金额) VALUES(11,'102','2019-6-12',NULL,0,0);
INSERT INTO 借阅(借书证编号, 图书编号,借书日期,还书日期,是否续借,罚款金额) VALUES(12,'103','2019-6-20',NULL,0,0);
INSERT INTO 借阅(借书证编号, 图书编号,借书日期,还书日期,是否续借,罚款金额) VALUES(13,'104','2019-6-21',NULL,0,0);
INSERT INTO 借阅(借书证编号, 图书编号,借书日期,还书日期,是否续借,罚款金额) VALUES(14,'107','2019-6-20',NULL,0,0);
INSERT INTO 借阅(借书证编号, 图书编号,借书日期,还书日期,是否续借,罚款金额) VALUES(15,'106','2019-6-21',NULL,0,0);
INSERT INTO 借阅(借书证编号, 图书编号,借书日期,还书日期,是否续借,罚款金额) VALUES(15,'105','2019-6-22',NULL,0,0);
/*在罚款交费单表插入5行数据 */

INSERT INTO 罚款交费单(交费单号,日期,职工编号,金额,借书证编号)  
VALUES(1,'2019-6-22',10001,10,10);
INSERT INTO 罚款交费单(交费单号,日期,职工编号,金额,借书证编号)  
VALUES(2,'2019-6-22',10004,20,12);
INSERT INTO 罚款交费单(交费单号,日期,职工编号,金额,借书证编号)  
VALUES(3,'2019-6-22',10005,30,13);


6.2测试查询语句
 

1 完成设计报告《6.1完整的测试数据》

 查询图书表,看看结果是否正确,截图到设计报告. (注意报损的图书册数未计入, 应如何解决?)

SELECT *
FROM 图书


 

查询读者表,看看结果是否正确,截图到设计报告.

SELECT *
FROM 读者


 

2  完成设计报告《6.2 测试查询语句》。

写出下列SQL语句并运行通过

  例如:写出用LIKE的查询要求, 并写出查询语句.

    查询要求:

查询书名中含有’数据库’的图书编号,书名

          查询语句:

SELECT 图书编号,书名 
FROM 图书
WHERE 书名 LIKE ‘%数据库%’


   

(1)    写出用到2表连接的查询要求, 并写出查询语句.

SELECT 出版社.出版社编号,出版社名称,出版社地址
FROM  出版社,图书
WHERE 图书.出版社编号=出版社.出版社编号
 

(2)    写出用到3表连接的查询要求, 并写出查询语句.

SELECT *
FROM  读者,图书,借阅
WHERE 图书.图书编号=借阅.图书编号 AND 读者.证书编号=借阅.借书证编号
 

(3)    写出用到GROUP BY的查询要求, 并写出查询语句.

SELECT 图书.图书类型编号,书名
FROM  图书,图书类型
WHERE 图书.图书类型编号=图书类型.图书类型编号
GROUP BY 图书.图书类型编号,书名
 

(4)    写出用到IN 子查询的查询要求, 并写出查询语句.

查询出版社地址在北京的图书


SELECT 书名
FROM 图书
WHERE 出版社编号 IN
(
SELECT 出版社编号
FROM 出版社
WHERE 出版社地址='北京'
)

(5)    写出用到NOT IN 子查询的查询要求, 并写出查询语句.

查询出版社地址不在北京的图书


SELECT 书名
FROM 图书
WHERE 出版社编号 NOT IN
(
SELECT 出版社编号
FROM 出版社
WHERE 出版社地址='北京'
)

(6)    写出用到EXISTS子查询的查询要求, 并写出查询语句.


SELECT 书名
FROM 图书
WHERE EXISTS
(
SELECT *
FROM 出版社
WHERE 图书.出版社编号=出版社.出版社编号 AND 出版社地址='北京'
)

(7)    写出用到NOT EXISTS子查询的查询要求, 并写出查询语句.


SELECT 书名
FROM 图书
WHERE NOT EXISTS
(
SELECT *
FROM 出版社
WHERE 图书.出版社编号=出版社.出版社编号 AND 出版社地址='北京'
)
 

(8)对每个视图,写出查询语句

1.入库单视图

SELECT *
FROM 入库单
 

2.报损单视图

SELECT *
FROM 报损单
 

3.读者未还借书视图

SELECT *
FROM 读者未还借书
 

4.图书分类库存视图

SELECT *
FROM 图书分类库存
 

4.借出次数前100图书视图

SELECT *
FROM 借出次数前100图书
 

第7章 结论
7.1 创新和特点
  数据库的概念设计,对E-R图的设计和简化;数据库的逻辑结构设计,建立起表结构;建立索引,索引表结构的设计;SQL建表,建立存储过程,建立触发器,数据插入后的测试。

7.2 遇到的主要问题和解决方法
在数据库概念设计中对各个实体性的确立和划分,这要从图书管理使用的实际出发,确定实体型和各个实体之间关系。

在E-R图向关系模式转换的过程中要明确好主码、外码等属性,建立好各个表之间的逻辑结构。

7.3 进一步改进的设想
该图书借阅管理系统还存在着许多问题,在逻辑结构设计的过程中一些表虽然减少了冗余,但在查询使用的过程中却存在着语句复杂,使用复杂的问题。同时用于实时检验和修改的触发器设计过于简陋,触发器数量太少,使得该系统不太成熟。

7.4 课程设计体会
通过对图书借阅管理系统的设计,一方面让我明白了数据库原理在图书管理上运用的流程,另一方面也让我初步了解了SQL-server 2017的开发工具的使用方法,熟悉了SQL建立数据库的一系列过程。在课程设计的过程中也遇到了一些问题,但是通过请教老师和同学讨论,解决了不少问题,对数据库系统原理也用了一个体系化的理解,收获很大。

7.5 学习数据库系统原理后的体会
   数据库的使用和高级程序开发的关系密不可分,学好数据库系统原理对于进一步理解程序设计流程和软件开发应用有着很大作用,通过本学期数据库系统原理的学习,虽然现在还没有真正使用数据库和高级语言一起用于程序的开发,但对开发流程和其中用到的数据库原理已经有所理解了。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐