目录
前言一、存储过程(一)存储过程的定义(二)存储过程的特点(三)存储过程的分类1、用户存储过程2、系统存储过程3、扩展存储过程(四)存储过程的创建(五)存储过程的执行(六)带参数的存储过程的使用1、带默认参数的存储过程2、带输入参数的存储过程3、带输出参数的存储过程4、带返回值的存储过程(七)存储过程的修改(八)存储过程的删除二、触发器(一)触发器的定义(二)触发器的特点和分类1、触发器的特点2、触发器的分类(三)触发器中使用的特殊临时表1、INSERTED临时表2、DELETED临时表(四)DML触发器1、AFTER触发器2、INSTEAD OF触发器(五)DDL触发器(六)创建触发器(七)使用触发器1、使用AFTER触发器2、使用INSTEAD OF触发器(八)修改触发器(九)删除触发器(十)触发器的启用和禁用结语前言
本章内容将介绍数据库中的存储过程和触发器,并将通过定义以及使用和验证其功能。
注:以下皆通过T-SQL语句进行操作,另一种图形界面自行翻阅书籍或网上搜索。
一、存储过程
(一)存储过程的定义
简单的来说,存储过程就是一串T-SQL语句集合
,通过定义后,可以使用该存储过程。
(二)存储过程的特点
它有以下特点:
1、可以快速执行。
相较于批处理语句,存储过程可以更快的执行,省去了重新分析、重新编译、重新优化等步骤。
2、具有安全特性。
3、可以减少网络通信流量。
4、可-被重复调用任意次,且可以保证功能的一致性。
(三)存储过程的分类
可以分为三类,即用户存储过程、系统存储过程、扩展存储过程,这里简单介绍这三种类型:
1、用户存储过程
用户存储过程即用户自己创建的存储过程,其中包括T-SQL存储过程和CLR存储过程(CLR存储过程这里不重点讲述),T-SQL存储过程即使用T-SQL语句创建的语句集合,通过接收和返回用户输入的参数执行该存储过程。
2、系统存储过程
系统存储过程是由系统本身所定义的存储过程,可以作为命令来执行,系统存储过程一般定义在系统数据库master中,都是以前缀sp_开头的,如下图。
3、扩展存储过程
扩展存储过程是指允许使用编程语言来创建自己的外部例程,添加至系统后也是按照存储过程的方法执行。
(四)存储过程的创建
语句格式如下:
CREATE PROC/PROCEDURE <存储过程的名称>(@参数的名称 类型...)/*定义参数的类型*/ASSQL语句...
上面的定义参数,会在后面的带参数的存储过程的使用中详细讲解。
例1、根据以下所给信息,在数据库Sales中,创建一个存储过程proc_1:其功能是显示商品信息表中出库存量最少的5条商品信息。
sql语句:
USE Sales GO CREATE PROC proc_1 AS SELECT TOP 5* FROM Product ORDER BY stocks ASC
可以发现命令完成后,在数据库Sales的可编编程性中的存储过程中找到所创建的存储过程dbo.proc_1。
注:当我们创建一个存储过程执行后,再点击执行会无法执行报错“已存在名为…的对象”,若我们不想再通过代码来修改存储过程的内容,可以在左侧对象资源管理器中找到相应的存储过程名右键删除,此时再点执行,执行已修改的存储过程。
(五)存储过程的执行
通过使用EXEC
或EXECUTE
命令来执行所创建的存储过程。
语句格式如下:
EXEC <已创建的存储过程名称>
例2、执行例1中创建的存储过程proc_1。
sql语句:
USE Sales GO EXEC proc_1
(六)带参数的存储过程的使用
存储过程带参数可以在存储过程和用户之间交换数据,有两种传递参数的方式,一是按位置传递参数
,即采用实参列表方式
,使传递参数和定义时的参数顺序一致;二是通过参数名称来传递参数,即参数=值的方式来传递,这钟方式的每个参数的顺序可以任意排列。
1、带默认参数的存储过程
在创建存储过程时,可以为带参数的存储过程设置为默认值,默认值必须为常量或NULL
。当用户调用存储过程时,如果未指定
对应的实参值,则自动使用对应的默认值进行替代。
2、带输入参数的存储过程
要定义带输入参数的存储过程,就必须要在创建语句中声明一个或多个变量及其类型
。
语句格式如下:
<@参数名> 类型 ... /*定义参数时*/WHERE <@参数名>=名称 ... /*WHERE赋值参数时*/EXEC <已创建的存储过程名称> <@参数名>/<@参数名>='输入值' .../*在执行存储过程时*/
例3、根据以下所给信息,在数据库Sales中,创建一个带默认参数的存储过程proc_2,其功能是:输入销售员的工号,输出指定销售员工号的销售员信息,指定默认工号为“S01”。
这里把创建存储过程和执行存储过程放在一起,为了方便执行,同时在执行存储过程中输入的参数采用的是按位置传递参数方式。
首先我们查询工号为“S02”的员工信息,,结果如下:
sql语句:
USE Sales GO CREATE PROC proc_2 @SaleID char(3)='S01' AS SELECT * FROM Seller WHERE SaleID=@SaleID GO EXEC proc_2 S02
因为事先已指定默认参数为“S01”,若我们不指定输入值,输出结果则会为工号为“S01”的员工,这里也是在执行存储过程中输入的参数采用的是按位置传递参数方式,结果如下:
sql语句:
USE Sales GO CREATE PROC proc_2 @SaleID char(3)='S01' AS SELECT * FROM Seller WHERE SaleID=@SaleID GO EXEC proc_2
例4、根据以下所给信息,在数据库Sales中,创建一个带默认参数的存储过程proc_3,其功能是:输入销售员的工号和性别,输出指定销售员工号的信息,指定默认工号为“S01”、默认性别为“男”。
> 这里我们定义了两个参数,分别是@SaleID和@Sex,在执行存储过程中输入的参数采用的是通过参数名传递参数方式,指定工号未“S08”,而未指定性别,所以采用的是默认性别。
sql语句:
USE Sales GO CREATE PROC proc_3 @SaleID char(3)='S01', @Sex char(2)='男' AS SELECT * FROM Seller WHERE SaleID=@SaleID AND Sex=@Sex GO EXEC proc_3 @SaleID='S08'
而当我们要查询“工号为“S03”的女销售员李芳时,由于默认指定性别为男,所以没有结果。
3、带输出参数的存储过程
定义输出参数可以从存储过程中返回一个或多个值到用户
,这里要注意,在定义带输出参数的存储过程的时,在创建语句和执行语句中必须要使用OUTPUT关键字。
语句格式如下:
<@参数名> 类型 OUTPUT... /*定义参数时*/WHERE <@参数名>=名称 ... /*WHERE赋值参数时*/DECLARE <@形参名> 类型...EXEC <已创建的存储过程名称> <@参数名> OUTPUT.../*在定义形参为输出参数和执行存储过程时*/
例5、根据以下所给信息,在数据库Sales中,创建一个带有输入参数和输出参数的存储过程proc_4:其功能是通过一个给定的销售员工号,查询出该销售员销售的商品总量及销售总金额,并通过输出参数进行返回。
首先为了得到查询出该销售员销售的商品总量及总金额,要定义了三个参数,分别是一个输入参数:代表销售员的工号、两个输出参数:分别代表销售商品总量及销售总金额。同时在SELECT语句中使用SUM()函数对多个销售商品数量和销售金额进行合计。然后在执行语句中通过DECLARE语句定义输出参数,并输出。
sql语句:
USE Sales GO CREATE PROC proc_4 @saleID char(3), @quantity int OUTPUT, @total money OUTPUT AS SELECT @quantity=SUM(quantity),@total=SUM(total) FROM orders,OrderDetail WHERE Orders.OrderID=OrderDetail.OrderID AND Orders.SaleID=@saleID GO DECLARE @quantity int DECLARE @total money EXEC proc_4 S03,@quantity output,@total output PRINT '该销售员销售总量为:'+ str(@quantity)+ ',总金额为:'+str(@total)
4、带返回值的存储过程
存储过程执行后会返回整型状态,若返回代码为0,表示成功执行
;若返回代码为-1~-99之间的整数,表示没有成功执行
,可使用RETURN关键字
进行返回。
例6、根据以下所给信息,在数据库Sales中,创建一个带有返回值的存储过程proc_5:其功能是通过一个给定的商品编号,查询该商品的库存情况,库存量大于等于500返回1,小于500返回0。
sql语句:
USE Sales GO CREATE PROC proc_5 @ProductID char(6) AS declare @x int select @x=stocks FROM Product WHERE ProductID=@ProductID IF @x>=500 return 1 ELSE return 0 GO DECLARE @s int EXEC @s = proc_5 'P01001' PRINT str(@s)
(七)存储过程的修改
使用ALTER PROC语句
修改已存在的存储过程,其与创建存储过程相同,这里不再累述。
(八)存储过程的删除
使用DROP PROC语句
可以删除创建的存储过程。
语句格式如下:
DROP PROC <已创建的存储过程名称>...
二、触发器
(一)触发器的定义
简单的来说,触发器就是一个特殊类型的存储过程
,其特殊性就在于其在修改表数据时自动触发执行所定义的语句。它和存储过程的区别是:存储过程是通过其名称直接调用,而触发器是通过事件进行触发从而自动执行。
(二)触发器的特点和分类
1、触发器的特点
触发器较于存储过程首先是其自动执行,另外它是建立在表或视图上的
,而存储过程是建立在数据库上的。此外触发器可以实现比约束还更严谨的限制,从而防止被修改。
触发器:
存储过程:
2、触发器的分类
触发器分为DML触发器
和DDL触发器
,这里的DML和DDL的意义分别是数据操作语言
和数据定义语言
。
(三)触发器中使用的特殊临时表
这里我们要知道在执行触发器时,系统创建了两个特殊的临时表
,分别是INSERTED表和DELETED表,它们在触发器执行时被创建,执行完后消失
。
1、INSERTED临时表
当向数据表或视图中插入数据
时,INSERT触发器执行
,将新元组插入INSERTED临时表及基本数据表中,也就是说INSERTED表是包含了已插入元组的一个副本。
2、DELETED临时表
(1)当向数据表或视图中执行删除操作
时,DELETE触发器执行
, 将删除的元组存放到DELETED表中。
(2)而当向数据表或视图中执行更新操作
时,UPDATE触发器执行
,执行先删除后插入的命令,即先将数据表或视图中的旧元组移至DELETED表中,然后将修改后的新元组插入到INSERTED表中。
(四)DML触发器
当数据库有数据操作语言事件时
,将调用DML触发器,这里包括修改表或视图数据
的INSERT语句、UPDATE语句、DELETE语句,即执行增删改操作。如果检测到错误,DML触发器还可以实现整个事务的自动回滚
。DML触发器分为AFTER触发器和INSTEAD OF触发器,它们触发条件差不多只不过执行的方式不同。
1、AFTER触发器
后触发型触发器
,当用户对表或视图执行INSERT语句、UPDATE语句、DELETE语句之后
,触发器被触发。
2、INSTEAD OF触发器
前触发型触发器
,当用户对表或视图执行INSERT语句、UPDATE语句、DELETE语句之后,系统不立即执行这些操作
,而是将操作内容交给触发器来检查操作是否正确
,若正确才继续执行。
(五)DDL触发器
当有对数据定义事件的修改时执行
,例CREATE语句、ALTER语句、DROP语句时才被触发,一般用于执行数据库中的管理任务,防止数据表结构被修改等等。
(六)创建触发器
要注意CREATE TRIGGER必须是批处理中的第一条语句,即在USE <表或视图> 后面要加GO批处理,且触发器只能应用到一个表中。
语句格式如下:
CREATE TRIGGER <触发器的名称> ON <表或视图的名称>AFTER/INSTEAD OF INSERT (UPDATE/DELETE)/*指定触发器类型以及触发器的语句类型:插入新行或更改某行或删除某行*/ASSQL语句
(七)使用触发器
1、使用AFTER触发器
例7、创建Product表的插入触发器tri_1:其功能是当向该表中插入一条新商品记录后,则提示“向Product表中添加了XXX商品记录”。并验证该触发器。
sql语句:
USE Sales GO CREATE TRIGGER trigger_1 ON Product AFTER INSERT AS DECLARE @ProductName varchar(30) select @ProductName=ProductName FROM INSERTED PRINT '向Product表中添加了'+@ProductName+'商品记录' GO INSERT Product(ProductID,ProductName,CategoryID,Price,stocks) VALUES('P05001','美汁源2000ml','3','13.5','2699')
例8、创建Category表的UPDATE触发器trigger_2:其功能是防止用户修改Category表中的分类序号ID。并验证该触发器。
这里的ROLLBACK TRANSACTION即为事务回滚,由于进行了事务回滚,回滚到更新操作之前的状态,所以没有修改CategoryID为1的日用品的CategoryName列的修改。
sql语句:
USE Sales GO CREATE TRIGGER trigger_2 ON Category AFTER UPDATE AS IF UPDATE(CategoryName) BEGIN PRINT '不能修改分类名称' ROLLBACK TRANSACTION END GO --验证该触发器 USE Sales UPDATE Category SET CategoryName='水果' WHERE CategoryID='1' GO
2、使用INSTEAD OF触发器
与AFTER触发器不同,INSTEAD OF触发器在触发时只执行触发器内部的T-SQL语句,而不执行激活该触发器的T-SQL语句。
例9、创建Category表的INSTEAD OF触发器trigger_3:其功能是防止用户对该表的任何数据进行删除。并验证该触发器。
这里由于定义了INSTEAD OF触发器,所以并未删除Category表的记录。
sql语句:
USE Sales GO CREATE TRIGGER trigger_3 ON Category INSTEAD OF DELETE AS PRINT '不能删除该表的数据!' GO --验证该触发器 USE Sales DELETE Category WHERE CategoryID='1' GO
(八)修改触发器
修改触发器使用ALTER TRIGGER语句进行修改,与创建触发器相同,只不过修改DML、DDL触发器不一样。
(九)删除触发器
删除触发器使用DROP TRIGGER语句进行删除,语句格式如下:
DROP TRIGGER <触发器名称>
(十)触发器的启用和禁用
若暂时不需要使用某个触发器,我们可以禁用该触发器,使用的T-SQL语句是ENABLE/DISABLE TRIGGER语句。
语句格式如下:
ENABLE/DISABLE TRIGGER ON <表或视图的名称>
结语
以上就是本次数据库原理与应用的全部内容,篇幅较长,感谢您的阅读和支持,若有表述或代码中有不当之处,望指出!您的指出和建议能给作者带来很大的动力!!!