/*
1. IN表示的嵌套
*/# (1) 查询至少借阅了一本图书的读者编号、姓名和单位。select rno,rname,dept from reader where rno in(select rno from borrow)# (2) 查询2016年一次也没借阅过的读者编号、姓名和单位。select rno,rname,dept from reader where rno notin(SELECT rno from borrow whereyear(borrowtime)=2016)# (3) 查询还未归还的图书的书号、书名和出版社(还书时间为空的表示未还)。select bno,bname,press from book where bno in(select bno from borrow where backtime isnull)#(4) 查询借阅了红楼梦的读者编号、姓名和单位。select rno,rname,dept from reader where rno in(select rno from borrow where bno=(select bno from book where bname='红楼梦'))# (5) 查询至少借阅过书号为“B11001”和“B11003”两本图书的读者编号。select rno from borrow where bno='b11001'and rno in(select rno from borrow where bno='b11003')# (6) 查询借阅了“数据库原理”或“图形图像处理”的读者信息。select*from reader where rno in(SELECT rno from book naturaljoin borrow where reader.rno=borrow.rno and(book.bname='数据库原理'or book.bname='图形图像处理'))select reader.*from reader naturaljoin borrow naturaljoin book where book.bname='数据库原理'or book.bname='图形图像处理';select*from reader where rno in(select rno from borrow where bno in(select bno from book where bname in('数据库原理','图形图像处理')));# (7) 查询借阅图书有过迟还行为的读者信息(迟还费大于0的)。select*from reader where rno in(select rno from borrow where latefee>0)select reader.*from reader naturaljoin borrow where latefee >0
比较符表示嵌套
/*
2. 比较符表示的嵌套
*/# (8) 查询借阅了红楼梦的读者编号、姓名、单位和借书时间。select*from reader where rno =(select rno from borrow naturaljoin book where book.bname='红楼梦')# (9) 查询职工号比“张旗”大而年龄比他小的职工的职工号、姓名和年龄。select zno,zname,age from employee where
zno>(select zno from employee where zname='张旗')and age<(SELECT age from employee where zname='张旗')# (10) 查询年龄大于所有女职工年龄的男职工的信息(用ALL表示)。select*from employee where age>all(select age from employee where sex='女')and sex ='男'# (11) 查询年龄至少比一个女职工小的男职工的信息(用ANY表示)。select*from employee where age <any(select age from employee where sex='女')and sex ='男'
exists表示嵌套
/*
3. EXISTS表示的嵌套
*/# (12) 查询借阅了机械工业出版社出版的所有图书的读者编号、姓名、单位。select rno,rname,dept from reader wherenotexists(select book.bno from book where press='机械工业出版社'andnotexists(select*from borrow where book.bno=borrow.bno and reader.rno=borrow.rno))
简单统计
/*
1.简单统计
*/# (1) 查询女职工的人数和平均年龄。selectcount(*)as'总人数',avg(age)as'平均年龄'from employee where sex='女'# (2) 查询红楼梦被借阅次数。selectcount(*)as'借阅次数'from book naturaljoin borrow where bname='红楼梦'# (3) 查询年龄大于女职工平均年龄的男职工的姓名和年龄。select zname,age from employee where age>(selectavg(age)from employee where sex='女')and sex='男'# (4) 查询各单位年龄最大的读者的编号、姓名、年龄和单位(并列最大的要全在结果中,可以用where嵌套,也可用from嵌套)selectDISTINCT rno,rname,age,A.dept from reader as A innerjoin(select dept,max(age)as MA from reader groupby dept)as B on A.age=B.MA and A.dept=B.dept
select rno,rname,age,dept from reader as A where age=(selectmax(age)from reader as B where A.dept=B.dept);
/*
组合查询
*/# (13) 查询机械工业出版社和电子工业出版社出版的图书信息(使用组合查询)。select*from book where press='机械工业出版社'unionselect*from book where press='电子工业出版社'/*
限制查询结果数量
*/# (14) 查询职工表中第3-8条记录。select*from employee limit2,6# (15) 查询借阅所交费用最多的前3位读者,要求输出读者编号和所交费用select rno,sum(latefee+damagefee)as'所交费用'from borrow groupby rno orderby 所交费用 desclimit3
存储过程定义和调用
#(1) 创建一名为“seek_reader”的存储过程,按指定单位、指定姓名查询读者信息(单位名、姓名由参数提供)delimiter $$
createprocedure seek_reader (in dept_ varchar(20),in rname_ varchar(20))beginselect*from reader where dept = dept_ and rname=rname_;end$$
#(2) 使用“seek_reader”存储过程,查询文学院XXX的信息(XXX为自己的姓名),观察结果。call seek_reader('文学院','XXX')#(3) 创建一名为“count_rs”的存储过程,统计指定单位的读者人数,并通过参数带回统计结果。delimiter $$
createprocedure count_rs(inout count_ varchar(10))beginselectcount(*)into count_ from reader groupby dept having dept=count_;end$$
delimiter;#(4) 使用“count_rs”存储过程,查询信息工程学院的人数,并显示。dropprocedure count_rs
set@count_='信息工程学院';call count_rs(@count_);select@count_as 总人数;#(5) 创建一名为“update_rdage”的存储过程,修改指定单位、指定姓名的读者的年龄(单位名、姓名和年龄由参数提供)delimiter $$
createprocedure update_rdage(in dept_ varchar(10),in rname_ varchar(10),in age_ int)beginupdate reader set age=age_ where rname=rname_ and dept=dept_;end $$
delimiter;#(6) 使用“update_rdage”存储过程,将文学院XXX读者的年龄改为22岁(XXX为自己的姓名),观察结果。call update_rdage('文学院','XXX',22);select*from reader where rname='XXX'#(7) 删除“update_rdage”的存储过程dropprocedure update_rdage;
函数的定义和使用
#(8) 创建一名为“count_books”的函数,统计指定作者的出版的图书数。delimiter $$
createfunction count_books(zz varchar(10))returnsintREADSSQLDATA# 开启了二进制,不加该语句就会报错beginreturn(selectcount(*)from book groupby author having author=zz);end $$
#(9) 使用“count_books”函数,查询XXX出版的图书数(XXX为自己的姓名),并显示。select count_books('XXX')
触发器的使用
#(10) 为tsglxt数据库创建一个日志表tsglxt_log,记录insert、update、delete等事件,日志表tsglxt_log的结构如下:/*
字段名 类型及长度 主键 自定义约束 说明
id bigint 是 auto_increment 自动编号
user_name Varchar(30) NOT NULL 用户名,取user()函数值
tb_name Varchar(30) NOT NULL 触发的表名
event_type Varchar(20) NOT NULL 取insert、update、delete
logtime timestamp NOT NULL 时间,取now()函数值*/createtable tsglxt_log(id bigintauto_incrementprimarykey,
user_name varchar(30)notnull,
tb_name varchar(30)notnull,
event_type enum('insert','update','delete')notnull,
logtime timestampdefaultnow()notnull)#(11) 为book表创建一名为“del_bf_book”的删除触发器,功能是将book表删除的记录插入book_bak1表(book_bak1在实验一已创建,结构与book相同),并在日志表tsglxt_log中登记操作记录(user_name:user(),tb_name:book,event_type:delete,logtime:now)。delimiter $$
createtrigger del_bf_book before deleteon book
for each rowbegininsertinto book_bak1 values(old.bno,old.bname,old.press,old.price,old.author);insertinto tsglxt_log(user_name,tb_name,event_type,logtime)values(user(),'book','delete',now());end$$
#(12) 将book表书号为XXX的图书记录删除(XXX为图书作者是自己姓名的图书的书号,如果borrow表中有该书的借阅,请先删除这些借阅记录),观察book_bak1表和tsglxt_log表变化,分析触发器的执行情况。deletefrom book where bno='B81004'#(13) 为borrow表创建一名为“update_bf_borrow”的修改触发器,功能是当修改的损毁费(damagefee)大于书价的3倍时,将修改的损毁费改为书价的3倍,并在日志表tsglxt_log中登记操作记录(user_name:user(),tb_name:borrow,event_type:update,logtime:now)。delimiter $$
createtrigger update_bf_borrow before updateon borrow
for each rowbeginset@price=0;select price into@pricefrom book where bno=old.bno;if new.damagefee>3*@pricethenset new.damagefee=3*@price;endif;insertinto tsglxt_log (user_name,tb_name,event_type,logtime)values(user(),'borrow','update',now());end$$
#(14) 将borrow表id为22的借阅记录的damagefee改为300元(大于该书实际价格3倍),backtime改为当时系统日期,观察borrow表该借阅记录的damagefee实际值和tsglxt_log表的变化。update borrow set damagefee=300where id=22;select*from borrow where id=22;
事件的设计
#(15) 为tsglxt数据库创建一个event_test表,用于事件测试,日志表event_test的结构如下:#字段名 类型及长度 主键 自定义约束 说明#id int 是 auto_increment 自动编号#event_name Varchar(30) NOT NULL 事件名#event_time timestamp NOT NULL 发生时间,取now()函数值createtable event_test(id intauto_incrementprimarykey,
event_name varchar(30)notnull,
event_time timestampnotnull);##(16) 先开启事件功能,再创建一个事件event1,实现从事件创建开始,1分钟后结束,每隔10秒向event_test表中插入一条记录(event_name:event1,event_time:now())。create event event1 on schedule every 10second
ends CURRENT_TIMESTAMP+INTERVAL1minutedoinsertinto event_test(event_name,event_time)values('event1',now());#(17) 1分钟后查看event_test表,分析事件是否正确运行。select*from event_test
游标的使用
# (18) 创建一名为“seek_reader_deptname”的函数,返回reader表中所有单位名构成的字符串,如"文学院、旅游学院、信息工程学院……",要求用游标实现(字符串连接可使用concat_ws()函数)。delimiter $$
createfunction seek_reader_deptname()returnsvarchar(30)READSSQLDATAbeginDECLARE _STOP intdefault0;declare co varchar(20);declare res varchar(30);declare cur cursorforselect dept from reader groupby dept;DECLARECONTINUEHANDLERFORNOT FOUND SET _STOP=1;open cur;
loop1:loopfetch cur into co;if _STOP=1thenleave loop1;elseset res = concat_ws('、',res,co);endif;endloop loop1;close cur;return res;end$$
#(19) 调用“seek_reader_deptname”函数,查询reader表中所有单位名构成的字符串。select seek_reader_deptname()