储存过程的基础的创建和简单应用.docx
《储存过程的基础的创建和简单应用.docx》由会员分享,可在线阅读,更多相关《储存过程的基础的创建和简单应用.docx(52页珍藏版)》请在冰豆网上搜索。
储存过程的基础的创建和简单应用
储存过程的基础的创建和简单应用
CREATEPROCEDURE
创建存储过程,存储过程是保存起来的可以接受和返回用户提供的参数的Transact-SQL语句的集合。
可以创建一个过程供永久使用,或在一个会话中临时使用(局部临时过程),或在所有会话中临时使用(全局临时过程)。
也可以创建在Microsoft®SQLServer™启动时自动运行的存储过程。
语法
CREATEPROC[EDURE]procedure_name[;number]
[{@parameterdata_type}
[VARYING][=default][OUTPUT]
][,...n]
[WITH
{RECOMPILE|ENCRYPTION|RECOMPILE,ENCRYPTION}]
[FORREPLICATION]
ASsql_statement[...n]
参数
procedure_name
新存储过程的名称。
过程名必须符合标识符规则,且对于数据库及其所有者必须唯一。
有关更多信息,请参见使用标识符。
要创建局部临时过程,可以在procedure_name前面加一个编号符(#procedure_name),要创建全局临时过程,可以在procedure_name前面加两个编号符(##procedure_name)。
完整的名称(包括#或##)不能超过128个字符。
指定过程所有者的名称是可选的。
;number
是可选的整数,用来对同名的过程分组,以便用一条DROPPROCEDURE语句即可将同组的过程一起除去。
例如,名为orders的应用程序使用的过程可以命名为orderproc;1、orderproc;2等。
DROPPROCEDUREorderproc语句将除去整个组。
如果名称中包含定界标识符,则数字不应包含在标识符中,只应在procedure_name前后使用适当的定界符。
@parameter
过程中的参数。
在CREATEPROCEDURE语句中可以声明一个或多个参数。
用户必须在执行过程时提供每个所声明参数的值(除非定义了该参数的默认值)。
存储过程最多可以有2.100个参数。
使用@符号作为第一个字符来指定参数名称。
参数名称必须符合标识符的规则。
每个过程的参数仅用于该过程本身;相同的参数名称可以用在其它过程中。
默认情况下,参数只能代替常量,而不能用于代替表名、列名或其它数据库对象的名称。
有关更多信息,请参见EXECUTE。
data_type
参数的数据类型。
所有数据类型(包括text、ntext和image)均可以用作存储过程的参数。
不过,cursor数据类型只能用于OUTPUT参数。
如果指定的数据类型为cursor,也必须同时指定VARYING和OUTPUT关键字。
有关SQLServer提供的数据类型及其语法的更多信息,请参见数据类型。
说明对于可以是cursor数据类型的输出参数,没有最大数目的限制。
VARYING
指定作为输出参数支持的结果集(由存储过程动态构造,内容可以变化)。
仅适用于游标参数。
default
参数的默认值。
如果定义了默认值,不必指定该参数的值即可执行过程。
默认值必须是常量或NULL。
如果过程将对该参数使用LIKE关键字,那么默认值中可以包含通配符(*、_、[]和[^])。
OUTPUT
表明参数是返回参数。
该选项的值可以返回给EXEC[UTE]。
使用OUTPUT参数可将信息返回给调用过程。
Text、ntext和image参数可用作OUTPUT参数。
使用OUTPUT关键字的输出参数可以是游标占位符。
n
表示最多可以指定2.100个参数的占位符。
{RECOMPILE|ENCRYPTION|RECOMPILE,ENCRYPTION}
RECOMPILE表明SQLServer不会缓存该过程的计划,该过程将在运行时重新编译。
在使用非典型值或临时值而不希望覆盖缓存在内存中的执行计划时,请使用RECOMPILE选项。
ENCRYPTION表示SQLServer加密syscomments表中包含CREATEPROCEDURE语句文本的条目。
使用ENCRYPTION可防止将过程作为SQLServer复制的一部分发布。
说明在升级过程中,SQLServer利用存储在syscomments中的加密注释来重新创建加密过程。
FORREPLICATION
指定不能在订阅服务器上执行为复制创建的存储过程。
.使用FORREPLICATION选项创建的存储过程可用作存储过程筛选,且只能在复制过程中执行。
本选项不能和WITHRECOMPILE选项一起使用。
AS
指定过程要执行的操作。
sql_statement
过程中要包含的任意数目和类型的Transact-SQL语句。
但有一些限制。
n
是表示此过程可以包含多条Transact-SQL语句的占位符。
注释
存储过程的最大大小为128MB。
用户定义的存储过程只能在当前数据库中创建(临时过程除外,临时过程总是在tempdb中创建)。
在单个批处理中,CREATEPROCEDURE语句不能与其它Transact-SQL语句组合使用。
默认情况下,参数可为空。
如果传递NULL参数值并且该参数在CREATE或ALTERTABLE语句中使用,而该语句中引用的列又不允许使用NULL,则SQLServer会产生一条错误信息。
为了防止向不允许使用NULL的列传递NULL参数值,应向过程中添加编程逻辑或为该列使用默认值(使用CREATE或ALTERTABLE的DEFAULT关键字)。
建议在存储过程的任何CREATETABLE或ALTERTABLE语句中都为每列显式指定NULL或NOTNULL,例如在创建临时表时。
ANSI_DFLT_ON和ANSI_DFLT_OFF选项控制SQLServer为列指派NULL或NOTNULL特性的方式(如果在CREATETABLE或ALTERTABLE语句中没有指定的话)。
如果某个连接执行的存储过程对这些选项的设置与创建该过程的连接的设置不同,则为第二个连接创建的表列可能会有不同的为空性,并且表现出不同的行为方式。
如果为每个列显式声明了NULL或NOTNULL,那么将对所有执行该存储过程的连接使用相同的为空性创建临时表。
在创建或更改存储过程时,SQLServer将保存SETQUOTED_IDENTIFIER和SETANSI_NULLS的设置。
执行存储过程时,将使用这些原始设置。
因此,所有客户端会话的SETQUOTED_IDENTIFIER和SETANSI_NULLS设置在执行存储过程时都将被忽略。
在存储过程中出现的SETQUOTED_IDENTIFIER和SETANSI_NULLS语句不影响存储过程的功能。
其它SET选项(例如SETARITHABORT、SETANSI_WARNINGS或SETANSI_PADDINGS)在创建或更改存储过程时不保存。
如果存储过程的逻辑取决于特定的设置,应在过程开头添加一条SET语句,以确保设置正确。
从存储过程中执行SET语句时,该设置只在存储过程完成之前有效。
之后,设置将恢复为调用存储过程时的值。
这使个别的客户端可以设置所需的选项,而不会影响存储过程的逻辑。
说明SQLServer是将空字符串解释为单个空格还是解释为真正的空字符串,由兼容级别设置控制。
如果兼容级别小于或等于65,SQLServer就将空字符串解释为单个空格。
如果兼容级别等于70,则SQLServer将空字符串解释为空字符串。
有关更多信息,请参见sp_dbcmptlevel。
获得有关存储过程的信息
若要显示用来创建过程的文本,请在过程所在的数据库中执行sp_helptext,并使用过程名作为参数。
说明使用ENCRYPTION选项创建的存储过程不能使用sp_helptext查看。
若要显示有关过程引用的对象的报表,请使用sp_depends。
若要为过程重命名,请使用sp_rename。
引用对象
SQLServer允许创建的存储过程引用尚不存在的对象。
在创建时,只进行语法检查。
执行时,如果高速缓存中尚无有效的计划,则编译存储过程以生成执行计划。
只有在编译过程中才解析存储过程中引用的所有对象。
因此,如果语法正确的存储过程引用了不存在的对象,则仍可以成功创建,但在运行时将失败,因为所引用的对象不存在。
有关更多信息,请参见延迟名称解析和编译。
延迟名称解析和兼容级别
SQLServer允许Transact-SQL存储过程在创建时引用不存在的表。
这种能力称为延迟名称解析。
不过,如果Transact-SQL存储过程引用了该存储过程中定义的表,而兼容级别设置(通过执行sp_dbcmptlevel来设置)为65,则在创建时会发出警告信息。
而如果在运行时所引用的表不存在,将返回错误信息。
有关更多信息,请参见sp_dbcmptlevel和延迟名称解析和编译。
执行存储过程
成功执行CREATEPROCEDURE语句后,过程名称将存储在sysobjects系统表中,而CREATEPROCEDURE语句的文本将存储在syscomments中。
第一次执行时,将编译该过程以确定检索数据的最佳访问计划。
使用cursor数据类型的参数
存储过程只能将cursor数据类型用于OUTPUT参数。
如果为某个参数指定了cursor数据类型,也必须指定VARYING和OUTPUT参数。
如果为某个参数指定了VARYING关键字,则数据类型必须是cursor,并且必须指定OUTPUT关键字。
说明cursor数据类型不能通过数据库API(例如OLEDB、ODBC、ADO和DB-Library)绑定到应用程序变量上。
因为必须先绑定OUTPUT参数,应用程序才可以执行存储过程,所以带有cursorOUTPUT参数的存储过程不能通过数据库API调用。
只有将cursorOUTPUT变量赋值给Transact-SQL局部cursor变量时,才可以通过Transact-SQL批处理、存储过程或触发器调用这些过程。
Cursor输出参数
在执行过程时,以下规则适用于cursor输出参数:
对于只进游标,游标的结果集中返回的行只是那些存储过程执行结束时处于或超出游标位置的行,例如:
在过程中的名为RS的100行结果集上打开一个非滚动游标。
过程提取结果集RS的头5行。
过程返回到其调用者。
返回到调用者的结果集RS由RS的第6到100行组成,调用者中的游标处于RS的第一行之前。
对于只进游标,如果存储过程完成后,游标位于第一行的前面,则整个结果集将返回给调用批处理、存储过程或触发器。
返回时,游标将位于第一行的前面。
对于只进游标,如果存储过程完成后,游标的位置超出最后一行的结尾,则为调用批处理、存储过程或触发器返回空结果集。
说明空结果集与空值不同。
对于可滚动游标,在存储过程执行结束时,结果集中的所有行均会返回给调用批处理、存储过程或触发器。
返回时,游标保留在过程中最后一次执行提取时的位置。
对于任意类型的游标,如果游标关闭,则将空值传递回调用批处理、存储过程或触发器。
如果将游标指派给一个参数,但该游标从未打开过,也会出现这种情况。
说明关闭状态只有在返回时才有影响。
例如,可以在过程中关闭游标,稍后再打开游标,然后将该游标的结果集返回给调用批处理、存储过程或触发器。
临时存储过程
SQLServer支持两种临时过程:
局部临时过程和全局临时过程。
局部临时过程只能由创建该过程的连接使用。
全局临时过程则可由所有连接使用。
局部临时过程在当前会话结束时自动除去。
全局临时过程在使用该过程的最后一个会话结束时除去。
通常是在创建该过程的会话结束时。
临时过程用#和##命名,可以由任何用户创建。
创建过程后,局部过程的所有者是唯一可以使用该过程的用户。
执行局部临时过程的权限不能授予其他用户。
如果创建了全局临时过程,则所有用户均可以访问该过程,权限不能显式废除。
只有在tempdb数据库中具有显式CREATEPROCEDURE权限的用户,才可以在该数据库中显式创建临时过程(不使用编号符命名)。
可以授予或废除这些过程中的权限。
说明频繁使用临时存储过程会在tempdb中的系统表上产生争用,从而对性能产生负面影响。
建议使用sp_executesql代替。
sp_executesql不在系统表中存储数据,因此可以避免这一问题。
自动执行存储过程
SQLServer启动时可以自动执行一个或多个存储过程。
这些存储过程必须由系统管理员创建,并在sysadmin固定服务器角色下作为后台过程执行。
这些过程不能有任何输入参数。
对启动过程的数目没有限制,但是要注意,每个启动过程在执行时都会占用一个连接。
如果必须在启动时执行多个过程,但不需要并行执行,则可以指定一个过程作为启动过程,让该过程调用其它过程。
这样就只占用一个连接。
在启动时恢复了最后一个数据库后,即开始执行存储过程。
若要跳过这些存储过程的执行,请将启动参数指定为跟踪标记4022。
如果以最低配置启动SQLServer(使用-f标记),则启动存储过程也不会执行。
有关更多信息,请参见跟踪标记。
若要创建启动存储过程,必须作为sysadmin固定服务器角色的成员登录,并在master数据库中创建存储过程。
使用sp_procoption可以:
将现有存储过程指定为启动过程。
停止在SQLServer启动时执行过程。
查看SQLServer启动时执行的所有过程的列表。
存储过程嵌套
存储过程可以嵌套,即一个存储过程可以调用另一个存储过程。
在被调用过程开始执行时,嵌套级将增加,在被调用过程执行结束后,嵌套级将减少。
如果超出最大的嵌套级,会使整个调用过程链失败。
可用@@NESTLEVEL函数返回当前的嵌套级。
若要估计编译后的存储过程大小,请使用下列性能监视计数器。
性能监视器对象名性能监视计数器名称
SQLServer:
缓冲区管理器高速缓存大小(页面数)
SQLServer:
高速缓存管理器高速缓存命中率
高速缓存页
高速缓存对象计数*
*各种分类的高速缓存对象均可以使用这些计数器,包括特殊sql、准备sql、过程、触发器等。
有关更多信息,请参见SQLServer:
BufferManager对象和SQLServer:
CacheManager对象。
sql_statement限制
除了SETSHOWPLAN_TEXT和SETSHOWPLAN_ALL之外(这两个语句必须是批处理中仅有的语句),任何SET语句均可以在存储过程内部指定。
所选择的SET选项在存储过程执行过程中有效,之后恢复为原来的设置。
如果其他用户要使用某个存储过程,那么在该存储过程内部,一些语句使用的对象名必须使用对象所有者的名称限定。
这些语句包括:
ALTERTABLE
CREATEINDEX
CREATETABLE
所有DBCC语句
DROPTABLE
DROPINDEX
TRUNCATETABLE
UPDATESTATISTICS
权限
CREATEPROCEDURE的权限默认授予sysadmin固定服务器角色成员和db_owner和db_ddladmin固定数据库角色成员。
sysadmin固定服务器角色成员和db_owner固定数据库角色成员可以将CREATEPROCEDURE权限转让给其他用户。
执行存储过程的权限授予过程的所有者,该所有者可以为其它数据库用户设置执行权限。
示例
A.使用带有复杂SELECT语句的简单过程
下面的存储过程从四个表的联接中返回所有作者(提供了姓名)、出版的书籍以及出版社。
该存储过程不使用任何参数。
USEpubs
IFEXISTS(SELECTnameFROMsysobjects
WHEREname='au_info_all'ANDtype='P')
DROPPROCEDUREau_info_all
GO
CREATEPROCEDUREau_info_all
AS
SELECTau_lname,au_fname,title,pub_name
FROMauthorsaINNERJOINtitleauthorta
ONa.au_id=ta.au_idINNERJOINtitlest
ONt.title_id=ta.title_idINNERJOINpublishersp
ONt.pub_id=p.pub_id
GO
au_info_all存储过程可以通过以下方法执行:
EXECUTEau_info_all
--Or
EXECau_info_all
如果该过程是批处理中的第一条语句,则可使用:
au_info_all
B.使用带有参数的简单过程
下面的存储过程从四个表的联接中只返回指定的作者(提供了姓名)、出版的书籍以及出版社。
该存储过程接受与传递的参数精确匹配的值。
USEpubs
IFEXISTS(SELECTnameFROMsysobjects
WHEREname='au_info'ANDtype='P')
DROPPROCEDUREau_info
GO
USEpubs
GO
CREATEPROCEDUREau_info
@lastnamevarchar(40),
@firstnamevarchar(20)
AS
SELECTau_lname,au_fname,title,pub_name
FROMauthorsaINNERJOINtitleauthorta
ONa.au_id=ta.au_idINNERJOINtitlest
ONt.title_id=ta.title_idINNERJOINpublishersp
ONt.pub_id=p.pub_id
WHEREau_fname=@firstname
ANDau_lname=@lastname
GO
au_info存储过程可以通过以下方法执行:
EXECUTEau_info'Dull','Ann'
--Or
EXECUTEau_info@lastname='Dull',@firstname='Ann'
--Or
EXECUTEau_info@firstname='Ann',@lastname='Dull'
--Or
EXECau_info'Dull','Ann'
--Or
EXECau_info@lastname='Dull',@firstname='Ann'
--Or
EXECau_info@firstname='Ann',@lastname='Dull'
如果该过程是批处理中的第一条语句,则可使用:
au_info'Dull','Ann'
--Or
au_info@lastname='Dull',@firstname='Ann'
--Or
au_info@firstname='Ann',@lastname='Dull'
C.使用带有通配符参数的简单过程
下面的存储过程从四个表的联接中只返回指定的作者(提供了姓名)、出版的书籍以及出版社。
该存储过程对传递的参数进行模式匹配,如果没有提供参数,则使用预设的默认值。
USEpubs
IFEXISTS(SELECTnameFROMsysobjects
WHEREname='au_info2'ANDtype='P')
DROPPROCEDUREau_info2
GO
USEpubs
GO
CREATEPROCEDUREau_info2
@lastnamevarchar(30)='D*',
@firstnamevarchar(18)='*'
AS
SELECTau_lname,au_fname,title,pub_name
FROMauthorsaINNERJOINtitleauthorta
ONa.au_id=ta.au_idINNERJOINtitlest
ONt.title_id=ta.title_idINNERJOINpublishersp
ONt.pub_id=p.pub_id
WHEREau_fnameLIKE@firstname
ANDau_lnameLIKE@lastname
GO
au_info2存储过程可以用多种组合执行。
下面只列出了部分组合:
EXECUTEau_info2
--Or
EXECUTEau_info2'Wh*'
--Or
EXECUTEau_info2@firstname='A*'
--Or
EXECUTEau_info2'[CK]ars[OE]n'
--Or
EXECUTEau_info2'Hunter','Sheryl'
--Or
EXECUTEau_info2'H*','S*'
D.使用OUTPUT参数
OUTPUT参数允许外部过程、批处理或多条Transact-SQL语句访问在过程执行期间设置的某个值。
下面的示例创建一个存储过程(titles_sum),并使用一个可选的输入参数和一个输出参数。
首先,创建过程:
USEpubs
GO
IFEXISTS(SELECTnameFROMsysobjects
WHEREname='titles_sum'ANDtype='P')
DROPPROCEDUREtitles_sum
GO
USEpubs
GO
CREATEPROCEDUREtitles_sum@@TITLEvarchar(40)='*',@@SUMmoneyOUTPUT
AS
SELECT'TitleName'=title
FROMtitles
WHEREtitleLIKE@@TITLE
SELECT@@SUM=SUM(price)
FROMtitles
WHEREtitleLIKE@@TITLE
GO
接下来,将该OUTPUT参数用于控制流语言。
说明OUTPUT变量必须在创建表和使用该变量时都进行定义