这里我们给出一副流程图来介绍一下SQL语句的执行过程:

从图中,大家可以看到每一条SQL语句在执行前都需要从客户端发往数据库服务器,然后再服务器端编译、优化,最后再被执行。哪怕是相同的SQL语句,只要是在不同的时机执行,都需要重复地经历上述过程。如果有些SQL语句总是固定地做某些事情,除了面对的数据有变化以外,SQL本身是不会变化的,那么我们就应该考虑反复地发送、编译、优化是否必要?换句话说,为了提高这些SQL的执行效率,能否将这些SQL直接存到数据库服务器端,避免每次执行前的重复发送;提前执行一次编译和优化,产生既定的查询计划,避免每次执行前的重复编译优化?其实“存储过程”这种机制就是实现这样的想法。
存储过程的概念
◎ 存储过程是指经过预先编译的SQL语句的集合,可以以一种可执行的形式永久地存储在数据库中。
存储过程的特点
◎ 存储过程类似于程序设计语言中的过程与函数
◎ 存储过程可以接收参数,并以输出参数的形式返回多个参数给调用存储过程的过程或批处理;
◎ 存储过程可以包含对数据库进行查询、更新等编程语句,也可以调用其它的存储过程;
◎ 可以返回执行存储过程的状态值以反映存储过程的执行情况。
存储过程的优点
◎ 运行速度快;
◎ 模块化编程,增强代码的重用性和共享性;
◎ 直接在服务器端执行,减少网络通信量;
◎ 保证系统的安全性。
存储过程的类型
◎ 系统存储过程
以sp为前缀,存放在master数据库中;主要是从系统表中获取信息,从而为系统管理员管理SQLServer提供支持。
◎ 用户自定义存储过程
由用户创建并能完成某一特定功能的存储过程;尽量不要以sp为前缀;
存储过程的创建
CREATE PROC [ EDURE ] procedure_name [ ; number ]
[ { @parameter data_type } [ = default ] [ OUTPUT ]
] [ ,...n ]
AS sql_statement
◇ procedure_name
存储过程的名称;过程名必须符合标识符规则,且对于数据库及其所有者必须唯一。
◇ ;number
是可选的整数,用来对同名的过程分组,以便用一条DROP PROCEDURE 语句即可将同组的过程一起除去。
◇ @parameter
过程中的参数。在 CREATE PROCEDURE 语句中可以声明一个或多个参数。
◇ data_type
参数的数据类型。所有数据类型均可以用作存储过程的参数。
◇ default
参数的默认值。如果定义了默认值,不必指定该参数的值即可执行过程。默认值必须是常量或 NULL。
◇ OUTPUT
表明参数是返回参数。使用 OUTPUT 参数可将信息返回给调用过程。
◇ n 表示最多可以指定 2,100 个参数的占位符。
◇ AS
指定过程要执行的操作。
◇ sql_statement
过程中要包含的任意数目和类型的 Transact-SQL 语句。
下面举例来说明存储过程的创建。
【例1】在学生-课程数据库中创建一个存储过程,查看“张明”同学的基本信息和选修课程的情况。
create procedure student_course
as
select s.Sno,Sname,Cname,Grade
from Student s,Course c,SC sc
where s.Sno=sc.Sno and c.Cno=sc.Cno and Sname='张明'
存储过程创建时的注意事项
◎ 成功执行create procedure之后,存储过程名称将存储在sysobjects系统表中;而create procedure
语句的文本将存储在syscomments中。
◎存储过程的调用可以嵌套。
◎存储过程一般是用于完成数据查询和数据处理操作,因此在存储过程中不可以使用创建数据库对象的语
句。
存储过程的执行
EXEC [ UTE ] procedure_name[parameter]
【例2】执行上例中创建的存储过程student_course.
execute student_course
前面我们在谈到存储过程的特点时,提到存储过程是可以带参数的。那么如何给存储过程传入参数?或是如何通过参数来传递出存储过程的执行结果呢?下面我们通过若干例子来说明这一点。
【例3】在学生-课程数据库中创建一个存储过程,查看某位同学的基本信息和选修课程的情况。
create procedure student_course
@StudentName varchar(10)
as
select s.Sno,Sname,Cname,Grade
from Student s,Course c,SC sc
where s.Sno=sc.Sno and c.Cno=sc.Cno and Sname=@StudentName
上述存储过程的调用:
execute student_course '张明‘
或者
execute student_course @StudentName='张明'
说明:此处的语句“@StudentName varchar(10)”在存储过程内部声明了一个参数:参数名是StudentName,参数是字符串类型,长度为10。参数的声明符号是@。从调用的方法可以看出,通过参数@StudentName,调用者可以给存储过程student_course传入参数。
【例4】创建一个存储过程,返回选修某门课程的学生人数。
create procedure student_count
@CourseName varchar(20),
@StudentSum int output
as
select @StudentSum=count(*) from Course,SC
where Course.Cno=SC.Cno and Cname=@CourseName
上述存储过程的调用示例(通过上例中创建的存储过程查找选修了“数据库原理及应用”的学生人数):
declare @studentNum int
execute student_count '数据库原理及应用', @studentNum output
select 'The result is:',@studentNum
说明:从本例存储过程的定义中,大家看到了关键字“output”。“output”作用在一个参数之后,是表示这个参数是一个输出参数;与之对应的是标识参数为输入参数的"input",只不过"input"是默认值,所以一般可以省略,比如本例中的@CourseName就是一个默认的输入参数。在本例,大家可以看到通过输入参数@CourseName,调用者向存储过程传入了课程名称“数据库原理及应用”;而通过输出参数@StudentSum,存储过程向调用者返回了该课程的选修人数。同时大家也应该注意到:通过输出参数可以在存储过程调用之后来访问存储过程的执行结果。
【例5】创建一个存储过程,根据学号输出某位学生的基本情况。
create procedure student_query
@xh int, @name varchar(8) output,
@sex char(2) output,@age int output
as
select @name=Sname,@sex=Ssex,@age=Sage from student where Sno=@xh
上述存储过程的调用示例(通过上例中创建的存储过程查询学号为950001的学生的基本情况):
declare @name varchar(8);
declare @sex char(2)
declare @age int;
execute student_query '950001', @name output,@sex output,@age output
说明:本例主要是向同学们展示具有多个参数的存储过程的定义和执行情况。
存储过程的修改
修改的语法:
ALTER PROC [ EDURE ] procedure_name
[ { @parameter data_type } [ = default ] [ OUTPUT ]
] [ ,...n ]
AS sql_statement [ ...n ]
从修改的语法可以看出,对存储过程的修改和重新定义一个存储过程几乎没什么太大的区别。只不过我们是通过重新定义一个同名的存储过程覆盖掉原有的存储过程罢了。
修改示例:
alter proc student_query
@xh int, @name varchar(8) output,
@sex char(2) output,@age int output
as
select @name=Sname,@sex=Ssex,
@age=Sage from student where Sno=@xh
存储过程的删除
删除的语法:
DROP PROCEDURE { procedure } [ ,...n ]
删除示例:
【例6】删除已经存在的存储过程student_query。
drop procedure student_query