SQL图书馆部分功能
一、建表部分
管理员表,读者表,图书表,书籍表,借阅表,罚款表
建表前整理好各表主外键的关系,数据类型保持一致,最好画E-R图的草稿
```c
--------------读者学生表READERS(卡号,姓名,性别,院系,邮箱,卡状态)假设学生卡号为7位,教职工卡号为5位
--DROP TABLE READERS
--DELETE READERS
--SELECT * FROM READERS
CREATE TABLE READERS (
read_no char(10) primary key,
read_name char(10) not null,
read_sex char(2) ,
read_dept char(10),
Email char(10),
card_status char(10) default '正常'
);
--sex列约束为男、女
alter table READERS
add constraint sex_check check(read_sex='男' or read_sex='女')
--读者表插入数据
INSERT INTO readers(read_no,read_name,read_sex,read_dept,Email) values('read001','一号选手','男','计算机系','email001');
GO
---------------管理员表(工号,姓名,联系方式)
--drop adm
--SELECT * FROM ADM
CREATE TABLE ADM(
adm_no char(10) primary key,
adm_name char(10) ,
adm_number char(10)
);
--插入数据
INSERT INTO ADM VALUES ('adm001','管理员一号','number001');
GO
----------------图书类别表catalog(ISBN,cata_name,cata_price,cata_writer,cata_publish,cata_total)
--DROP TABLE CATALOG
--SELECT * FROM CATALOG
CREATE TABLE CATALOG
(
ISBN char(13) primary key,
cata_name char(10) ,
cata_price decimal(10,2),
cata_writer char(10),
cata_publish char(10),
cata_total int default 0,
adm_no char(10),
foreign key (adm_no) references ADM(adm_no)
)
GO;
-----------------图书表(图书ID,图书名称,状态,管理员工号)
--SELECT * FROM BOOKS
--DROP TABLE BOOKS
--ALTER TABLE BOOKS
--ADD book_name char(10)
CREATE TABLE BOOKS(
book_no char(20) primary key,
ISBN char(13),
book_name char(10),
book_status char(10) default'可借',
foreign key(ISBN) references CATALOG(ISBN)
);
--图书表中插入数据
--INSERT INTO BOOKS(book_no,ISBN,adm_no,book_name) values('book001','isbn001','adm001','天生有罪');
GO
-----------------FINE(借书证号,图书编号,罚款金额)
--SELECT * FROM FINE
CREATE TABLE FINE(
read_no char(10),
book_no char(20),
obey_money float,
constraint pk_fine primary key(read_no,book_no),
foreign key (read_no) references READERS(read_no),
foreign key (book_no) references BOOKS(book_no),
);
GO
-----------------借阅表(卡号,图书号,借书时间,应还时间,还书时间,续借状态)
--SELECT * FROM BORROW
--select * from books
--drop table borrow
CREATE TABLE BORROW(
read_no char(10),
book_no char(20),
borr_time date default convert(date,getdate()),
due_time date default convert(date,dateadd(month,1,getdate())),
return_time date,
renew_status char(10) default '未续借',
CONSTRAINT pk_borr PRIMARY KEY (read_no,book_no),
foreign key (read_no) references READERS(read_no),
foreign key (book_no) references BOOKS(book_no)
);
GO
二、图书录入功能
思路:
- 为catalog创建存储过程,输入ISBN,书名,价格,作者,出版社,册数,管理员工号
- 为catalog创建触发器,当向catalog插入数据时,自动向Books表中插入记录
(1) Books中记录条数与册数相同,用while(@i<册数)循环实现;
(2) 图书号book_no=concat(book,ISBN,@i)自动生成,ISBN,book_name从inserted表中获取,book_status默认为
可借。
---------------------------------------------------------------------录入功能-------------------------------------------------------------------------------------
---------------------------------------------------------------------INSERT CATALOG,BOOKS表自动插入BOOKS信息----------------------------------------------
GO;
---------Pro_InsertCatalog,图书管理员录入图书信息
CREATE PROCEDURE Pro_InsertCatalog
@ISBN char(13),
@cata_name char(10),
@cata_price decimal(10,2),
@cata_writer char(10),
@cata_publish char(10),
@cata_total int,
@adm_no char(10)
AS
BEGIN
INSERT INTO CATALOG VALUES(@ISBN,@cata_name,@cata_price,@cata_writer,@cata_publish,@cata_total,@adm_no);
END
GO;
----------Tri_InsertCatalog,向catalog插入信息时,自动向BOOKS表插入信息
--图书表(图书ID,图书名称,状态,管理员工号)
CREATE TRIGGER Tri_InsertCatalog ON CATALOG FOR INSERT AS
BEGIN
-----当catalog中插入图书册数为n时,BOOKS表需插入n条记录
DECLARE @cata_total int SET @cata_total=(SELECT cata_total FROM INSERTED)
DECLARE @ISBN char(13) SET @ISBN=(SELECT ISBN FROM INSERTED)
DECLARE @cata_name char(10) SET @cata_name=(SELECT cata_name FROM INSERTED)
DECLARE @i INT SET @i=1 --循环变量
WHILE(@i<=@cata_total)
BEGIN
--自动生成BOOKS的book_no=book+ISBN+@i
declare @book_no char(20) set @book_no=concat('book',@ISBN,convert(char(3),@i))
INSERT INTO BOOKS(book_no,ISBN,book_name) VALUES(@book_no,@ISBN,@cata_name)
set @i=@i+1
END
END
GO;
-----------测试图书录入功能
delete books
delete catalog
select * from catalog go;
select * from books;
exec Pro_InsertCatalog 'isbn123456001','图书一号',48.50,'作者一号','出版社一号',5,'adm001'
三、借书功能
思路:
1.存储过程pro_insertBorrow,输入读者卡号、图书编号,自动将该记录插入到borrow表
(1)借阅时间取当前系统时间getdate(),
(2)应还时间为dateadd(month,1,getdate()),(3)续借状态默认为未续借
2 触发器Tri_insertBorrow
(1) 从inserted表中提取信息,赋值给@read_no,@book_no
(2) 检查read_no对应的读者卡号是否挂失,挂失则rollback,不允许借书(3) 检查book_no对应的书籍是否可借阅,已被借阅则rollback,不允许借书
(4) 卡号正常,书可借时,更新books表中书编号@book_no的状态为不可借
------------------------------------------------------借阅功能,insert borrow时--------------------------------------
------------------------------------------------------将书状态改为不可借-----------------------------------------------
-------------------存储过程pro_InsertBorrow,输入read_no,ISBN,向BORROW中插入借阅记录
--DROP PROCEDURE pro_InsertBorrow
CREATE PROCEDURE pro_InsertBorrow @ReadNo char(10),@BookNo char(20) AS
BEGIN
INSERT INTO BORROW(read_no,book_no) VALUES(@ReadNo,@BookNo)
END
--------------------触发器Tri_InsertBorrow,向Borrow中插入借阅记录时,自动改变书的状态
GO
--drop trigger Tri_InsertBorrow
CREATE TRIGGER Tri_InsertBorrow ON BORROW FOR INSERT AS
BEGIN
------从insert 表中收集信息
declare @read_no char(10) set @read_no =(select read_no from inserted)
declare @book_no char(20) set @book_no =(select book_no from inserted)
print (@read_no)
print(@book_no)
--读者卡挂失
IF((select card_status from READERS where read_no =@read_no)='挂失')
BEGIN
rollback
print'此卡已挂失,不可借书'
END
--书已被借走,不可借阅
IF((select book_status from BOOKS where book_no =@book_no)='不可借' )
BEGIN
rollback
print '此书已被接走,不可借阅'
END
IF((select card_status from READERS where read_no =@read_no)='正常'
AND (select book_status from BOOKS where book_no =@book_no)='可借')
BEGIN
print'借书成功'
--更改BOOKS表中的book_status
UPDATE BOOKS
SET book_status='不可借'
WHERE book_no =@book_no
END
END
go;
-------------------------------------------测试借书功能Pro_InsertBorrow,Tri_InsertBorrow
select * from BOOKS;
select * from READERS;
select * from BORROW;
--delete borrow
UPDATE READERS SET card_status='正常' WHERE read_no='read001'
UPDATE BOOKS SET book_status='可借' WHERE book_no='bookisbn1234560011'
exec pro_InsertBorrow 'read001','bookisbn1234560011'
go;
四、还书功能
思路:
1 存储过程Pro_updateBorrowReturn,输入book_no,read_no,retur_time,更新borrow表中的还书时间
2 触发器Tri_updateBorrowReturn
(1) 从inserted表中提取信息,赋值给@read_no,@book_no,@return_time,@due_tiem;
(2)比较@due_tme,@return_time,datediff(day,@due_time,@return_time)>0则 超期,将读者 卡号,图书编号,罚款金额(超期天数*0.1)插入罚款表
(3)更新books表中图书编号为@book_no书籍的book_stutus为可借
------------------------------------------存储过程还书Pro_UpdateBorrowReturn,输入还书日期,更新归还时间
CREATE PROCEDURE Pro_UpdateBorrowReturn
@ReadNO char(10),
@BookNo char(20),
@ReturnTime date AS
BEGIN
UPDATE BORROW
SET return_time=@ReturnTime
WHERE read_no = @ReadNO AND book_no = @BookNo
END
go;
-----------------------触发器Tri_UpdateBorrowReturn 更新BORROW return_time时,将书改为可借,超期生成罚款单
--DROP TRIGGER Tri_UpdateBorrowReturn
CREATE TRIGGER Tri_UpdateBorrowReturn ON BORROW FOR UPDATE AS
BEGIN
declare @ReadNo char(10) set @ReadNo =(select read_no from inserted)
declare @BookNo char(20) set @BookNo=(select book_no from inserted)
declare @ReturnTime date set @ReturnTime=(select return_time from inserted)
declare @DueTime date set @DueTime=(select due_time from inserted)
--列级触发器
IF UPDATE(return_time)
BEGIN
--将书改为可借
UPDATE BOOKS SET book_status ='可借' WHERE book_no=@BookNo
--判断是否超期
IF (datediff(day,@DueTime,@ReturnTime)>0)
BEGIN
print '借书超期,超期一天罚款0.1元'
declare @dalay_day int set @dalay_day=abs(datediff(day,@DueTime,@ReturnTime))
declare @money float set @money=0.1*@dalay_day
INSERT INTO FINE VALUES (@ReadNo,@BookNo,@money);
END
END
END
go;
------------------------------------------------------测试还书功能,还书更新return_time,超期生成罚款单
select * from BOOKS;
select * from READERS;
select * from BORROW;
select * from FINE;
--delete borrow
--借书部分
UPDATE READERS SET card_status='正常' WHERE read_no='read001'
UPDATE BOOKS SET book_status='可借' WHERE book_no='bookisbn123456001'
exec pro_InsertBorrow 'read001','bookisbn1234560011'
--还书部分
exec Pro_UpdateBorrowReturn 'read001','bookisbn1234560011','2020-05-29'
go;
五、续借功能
思路:
总结:图书的是否被借阅过要从deleted的旧表中查看,inserted表肯定是显示为续借的。
1 存储过程Pro_updateBorrowDue 输入读者卡号,图书编号,实现book_status更新
2 触发器Tri__updateBorrowDue
(1) 从deleted表收集图书原来的book_status,read_no,book_no
(2) 如果book_status显示为已续借,则该读者已续借过一次,不可再次续借.
(3) 检查read_no字段的长度,如果为7位长,则为学生,可续借1个月,更新books表的due_time=dateadd(month,1,@due_time)
(4) 检查read_no字段的长度,如果为6位长,则为学生,可续借3个月,更新books表的due_time=dateadd(month,3,@due_time)
----------------------------------------------------续借存储过程Pro_UpdateBorrowDue,教职工卡考位8位,可续借三个月,学生卡号为10位,可续借一个月
--DROP PROCEDURE Pro_UpdateBorrowDue
CREATE PROCEDURE Pro_UpdateBorrowDue
@ReadNo char(10),
@BookNo char(20) AS
BEGIN
UPDATE BORROW SET renew_status = '已续借' WHERE read_no = @ReadNo AND book_no = @BookNo
END
GO;
---------------------------------------------------触发器续借Tri_UpdateBorrowDue,已续借不可续借,卡号7位可续借1个月,卡号6位可续借3个月
--DROP TRIGGER Tri_UpdateBorrowDue
CREATE TRIGGER Tri_UpdateBorrowDue ON BORROW FOR UPDATE AS
BEGIN
declare @ReadNo char(10) set @ReadNo=(select read_no from inserted)
declare @BookNo char(20) set @BookNo=(select book_no from inserted)
declare @RenewStatus char(10) set @RenewStatus=(select renew_status from deleted) -------------查看deleted表中续借状态
declare @DueTime date set @DueTime=(select due_time from inserted)
IF UPDATE(renew_status)
BEGIN
-----判断是否已续借
IF(@RenewStatus='已续借')
BEGIN
rollback
print'此书已续借,不可再次续借'
END
IF(@RenewStatus='未续借')
BEGIN
print'此书未续借,可续借'
-----判断是教师还是学生
print(len(@ReadNO))
IF(LEN(@ReadNo)=7)-----学生
BEGIN
---更新due_tim,renew_status
UPDATE BORROW SET due_time=CONVERT(date,dateadd(month,1,@DueTime) ) WHERE book_no =@BookNo AND read_no =@ReadNo
UPDATE BORROW SET renew_status='已续借' WHERE book_no =@BookNo AND read_no =@ReadNo
print'续借成功,已延期一个月'
END
IF(LEN(@ReadNo)=6)-----教师
BEGIN
---更新due_time, renew_status
UPDATE BORROW SET due_time=CONVERT(date,dateadd(month,3,@DueTime) ) where book_no =@BookNo AND read_no =@ReadNo
UPDATE BORROW SET renew_status='已续借' WHERE book_no =@BookNo AND read_no =@ReadNo
print'续借成功,已延期三个月'
END
END
END
END
GO;
---------------------------------------------------测试续借功能
select * from BOOKS;
select * from READERS;
select * from BORROW;
select * from FINE;
--delete borrow
--delete fine
--借书部分
UPDATE READERS SET card_status='正常' WHERE read_no='read001'
UPDATE BOOKS SET book_status='可借' WHERE book_no='bookisbn1234560011'
exec pro_InsertBorrow 'read001','bookisbn1234560011'
--续借部分
exec Pro_UpdateBorrowDue 'read001' ,'bookisbn1234560011'
-------------------------------------------教师借书
--借书部分
INSERT INTO READERS(read_no,read_name,read_sex,read_dept,Email) VALUES('Tea001','教师一号','男','计算机系','Email002')
UPDATE READERS SET card_status='正常' WHERE read_no='Tea001'
UPDATE BOOKS SET book_status='可借' WHERE book_no='bookisbn1234560012'
exec pro_InsertBorrow 'Tea001','bookisbn1234560012'
--续借部分
exec Pro_UpdateBorrowDue 'Tea001' ,'bookisbn1234560012'
GO;
六、查看一个学生的借阅的图书
存储过程 Pro_checkReaderBooks
(1) 输入读者卡号,返回读者借阅的图书名称和图书编号
(2) 将borrow和reader表自然连接,即读者卡号相同的连接,将卡号为输入卡号的元组筛选出来,投影出图书编号和图书名称两列
(3) SQL:select book_name,book_no
From reader inner jion borrow on reader.read_no =borrow.book_no
Where read_no = @Read_no
----------------------------------------------------------------查询某读者借阅的所有图书------------------------------------------------------------------------------------
-----------------------------------------------------------------Pro_checkReaderBooks
CREATE PROCEDURE Pro_checkReaderBooks
@read_no char(10),
@book_no char(20) output,
@book_name char(10) output
AS
BEGIN
set @book_no=
(SELECT borrow.book_no
FROM BORROW,BOOKS
WHERE borrow.book_no=books.book_no
AND read_no =@read_no)
set @book_name=
(SELECT books.book_name
FROM BORROW,BOOKS
WHERE borrow.book_no=books.book_no
AND read_no =@read_no)
END
go;
---------------测试
declare @BookNo char(20)
declare @BookName char(10)
exec Pro_checkReaderBooks 'read001', @BookNo output, @BookName output
print @BookNo
print @BookName
七、总结
1.连接字符串可以用concat(),以此自动生成book_no=concat(‘book’+’isbn’+@i)
当设值的大小大于isbn实际的大小时,concat连接会有空格
2 identity(初始值,步长)只能用于建表或修改表时的某一列,不能用于和isbn+identity(1,1)生成book_no
3.聚合函数的使用
select 的列名必须在group by 【列1】 中,因为group之后,【列1】值相同的记录归纳为一组了。