SQL server中使用存储过程与触发器

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_36027342/article/details/89306580

在示例中主要是对一个BooksDB数据库的数据进行处理的,如果有需要的可以看一下创建该数据库的代码

一.存储过程(stored procedure)

  •   为了完成一定功能的一组sql语句
  • 经过编译后存储到数据库
  • 系统存储过程_sp, 拓展存储过程_xp, 用户自定义存储过程_usp

1.优点(为什么要用存储过程)

    ①模块化编程

    ②减少网络的流量

    ③提高执行速度

    ④提高数据的安全性 

2.创建语句

create procedure 存储过程名 
		参数
as
		功能

--执行
exec 存储过程名

--调用语句为批处理的第一条语句时,可省略exec

示例:

1).不带参数的存储过程:创建一个存储过程,查看所有读者的姓名、可借本数、可借天数和已借书本数。

--1、	不带参数的存储过程:创建一个存储过程,查看所有读者的姓名、可借本数、可借天数和已借书本数。 

create procedure usp_selelctReader
as		
	select rdName,canLendQty,canLendDay,rdBorrowQty 
	from Reader, ReaderType 
	where Reader.rdType=ReaderType.rdType

--测试执行
exec usp_selelctReader

执行运行结果:

2).带输入参数和输出参数的存储过程:创建一个存储过程,输入读者的编号,输出该读者的姓名

--2、	带输入参数和输出参数的存储过程:创建一个存储过程,输入读者的编号,输出该读者的姓名; 
create procedure usp_getName
  @rdID char(9),
  @rdNmae varchar(20) output
as
  select @rdNmae=rdName from Reader where rdID=@rdID

--测试执行
declare @rdNmae varchar(20)
exec usp_getName'rd2018007',@rdNmae output
print @rdNmae

运行结果:卢小川

3). 带输入参数的存储过程:创建一个存储过程,实现借书功能

--3、	带输入参数的存储过程:创建一个存储过程,实现借书功能;
alter procedure usp_borrow
	@rdID char(9),
	@bkID char(9),
	@DateBorrow datetime,
	@DateLendPlan datetime
as
  begin tran
	print'begin tran'
	begin	try
	  --先判断图书状态
		declare @bkState int
		select @bkState=bkState from Book where bkID=@bkID
		if(@bkState!=1)
		  raiserror('借书失败!!该图书不在馆!',16,1)
		else
		  begin	
		--判断读者借书是否已满
			declare @rdBorrowQty int,@canLendQty int

			select @canLendQty=canLendQty,@rdBorrowQty=rdBorrowQty from Reader,ReaderType 
			where rdID=@rdID and Reader.rdType=ReaderType.rdType;

			if(@rdBorrowQty>=@canLendQty)
			   raiserror('借书失败!!该读者借书已达上限!',15,1)
		  else 
			    begin
				  insert into Borrow(rdID,bkID,DateBorrow,DateLendPlan) 
		      values(@rdID,@bkID,	@DateBorrow,@DateLendPlan);
			    --修改图书状态
					update Book set bkState=0 where bkID=@bkID;
					--修改借书数量
					update Reader set rdBorrowQty=rdBorrowQty+1 where rdID=@rdID;
					print @rdID+'借'+@bkID+'成功!!'
					commit
					print'commit'
		      end
		  end
	end try
	begin catch
	  DECLARE @ErrorMessage NVARCHAR(4000)
	  select @ErrorMessage = ERROR_MESSAGE()
	  raiserror(@ErrorMessage,16,1)
		rollback
		print'rollback'
	end catch

测试代码1:

--测试执行
declare @date datetime,@date_plan datetime
--获取当前时间为借书时间
set @date=GETDATE()
--计划还书时间为借书后的第十天
set @date_plan=GETDATE()+10 
exec usp_borrow'rd2018001','bk2018001',@date,@date_plan

运行结果:

再次运行

查询结果:

二.触发器

  • 是一特殊的存储过程,通过事件触发而执行的
  • 可以实现比primary key,foregin key,check,unique,default更加复杂的数据完整性约束
  • DML触发器:insert,delete,update
  • DDL触发器:create,alter,drop

两个特殊表(deleted,inserted):系统自动管理,动态驻留内存中

1.DML触发器

为什么使用触发器呢?先来看一个示例代码

--视图学号,姓名,课程号,课程名,成绩
create view view1
as
		select Student.Sno,Sname,Course.Cno,Cname,Grade
		from  Student,SC,Course
		where Student.Sno=SC.Sno and Course.Cno=SC.Cno

select * from view1

--结果会提示错误,因为修改会影响多个基表,因此可利用触发器,解决

--视图上只能创建instead of 触发器
create trigger tri_view1 on view1 instead of insert
as
		insert into Student(Sno,Sname) select Sno,Sname from inserted		
		insert into Course(Cno,Cname) select Cno,Cname from inserted
		insert into SC(Sno,Cno,Grade) select Sno,Cno,Grade from inserted

2.DDL,DDL事件组

create trigger tri_safe on database
--for create_table,drop_table,alter_table
for ddl_table_events
as
		print('数据表上的DDL触发器执行啦')
		print('您无法再该石油加油卡上创建表和创建表')
		rollback
--测试
create table test_table(
		no char(8),
		name char(20)
		)
select * from test_table

3.服务器触发器

create trigger tri_CheckLogin on all server 
 for  ddl_table_events
 as
		rollback
		print('不能再该数据库上创建,删除,修改登录账号')

create login aa with password='sa123'

--禁用
disable trigger all on all server

4.触发器运用示例

1)创建 DDL 触发器,禁止用户修改 BooksDB 数据库中的表;

实现代码:

创建 DDL 触发器,禁止用户修改 BooksDB 数据库中的表; 
create trigger tri_safe on Database
--for create_table,drop_table,alter_table
for ddl_table_events
as
	rollback
	print('DDL触发器执行啦')
	print('您无法在该数据库上修改表')
go
--测试
drop table Borrow

运行结果:

注:go--是批处理结束的语句.批处理:一条或多条SQL语句,一次性发送到SQL sever数据库服务器进行执行,SQL server数据库服务器讲批处理的语句编译成一个可执行单元,称为执行计划,当编译错误的时候不会执行;运行时错误;

2)测试 AFTER 触发器,理解 INSERTED 表和 DELETED 表的作用;

实现代码:

--测试 AFTER 触发器,理解 INSERTED 表和 DELETED 表的作用;
create trigger tri_testAfter on Borrow
for insert,delete
as
  select * from inserted
	select * from deleted
	print'Borrow表上的afetr触发器执行啦!'

--测试

insert into Borrow values('rd2018007','bk2018001',GETDATE(),GETDATE()+10,default)

select * from Borrow

delete Borrow where rdId='rd2018007'

运行结果:

思考题1: 请在SC表上创建一个触发器,当删除SC表中的选课记录时,要求平均成绩表自动更新

实现代码:

--思考:请在SC表上创建一个触发器,当删除SC表中的选课记录时,要求平均成绩表自动更新

--创建平均成绩表
select sno,avg(Grade) avgGrade into avgTable from SC group by sno

--创建触发器
create trigger tri_delSC on SC
for delete
as
	print'SC表上的delete触发器执行啦!'
	declare @sno char(9)
	set @sno=(select Sno from deleted)	
	update avgTable set avgGrade=(select avg(Grade) from SC  where sno=@sno group by sno) where sno=@sno
	print'平均成绩表更新啦'

--测试执行
  select * from avgTable
	select * from SC
	delete SC where sno='2017003' and Cno='2'
--查看数据
  select * from avgTable
	select * from SC

运行结果:

思考题2: 请在SC表上创建一个触发器,当更新SC表中的选课成绩时,要求平均成绩表自动更新

实现代码:

--思考:请在SC表上创建一个触发器,当更新SC表中的选课成绩时,要求平均成绩表自动更新


select sno,avg(Grade) avgGrade into avgTable from SC group by sno


create trigger tri_updateSC on SC
for update
as
	print'SC表上的update触发器执行啦!'
	declare @sno char(9)
	set @sno=(select Sno from inserted)	
	update avgTable set avgGrade=(select avg(Grade) from SC  where sno=@sno group by sno) where sno=@sno
	print'平均成绩表更新啦'

--测试执行

  select * from avgTable
	update SC set Grade=99 where sno='2017003' and Cno='1'
--查看数据
  select * from avgTable
	select * from SC

运行结果:

三.总结:

  1. 过程可以带输入输出参数,可以不带参数
  2. 在调用过程时,如果参数是datetime类型的,不能直接写GETDATE(),如果想传入当前时间,可以引用一个变量来存储GETDATE()的值,然后调用时传出参数写变量名
  3. DDL触发器,可以写具体的操作如: create_table,drop_table,alter_table;也可以直接写事件组: ddl_table_events
  4. 两个特殊表,deleted,inserted.系统自动管理,动态驻留内存中
  5. 如果创建了一个视图,该视图的基表有多个,在进行插入数据的时候会提示错误,以为修改会影响多个基表,此时可以利用触发器联合inserted表来对每一个基表进行插入
  6. 可以创建服务器触发器:on all server;如果禁用触发器使用:disable trigger all on all server
  7. 在对数据进行插入修改操作时,可以使用事务,进行提交回滚
  8. 错误提示:raiserror

猜你喜欢

转载自blog.csdn.net/weixin_36027342/article/details/89306580
今日推荐