您的位置:首页 > 数据库

【SQL Server学习笔记】存储过程、sp_executesql存储过程、try catch错误处理

2012-08-10 15:25 295 查看
存储过程就是把一个或多个T-SQL语句组合到一个逻辑单元中,在SQL Server数据库中保存为一个对象。在创建完成后,定义会保存在sys.sql_modules系统目录视图中。
存储过程的有点:
1、存储过程是在数据层汇集的T-SQL代码,可以促进代码的重复使用,同时有助于调试、寻找bug。也就是说这些代码就存放在数据库里,而不是嵌入在应用程序中的SQL代码,再由这些代码连接起来,最后发送到服务器上来执行的。
2、存储过程相对于大的即席查询,能够减少网络流量。
3、存储过程则更安全,因为内嵌的即席查询容易进行SQL注入。
4、相对于函数、视图,存储过程能使用流控制、临时表、表变量等。
5、可以淡化数据获取的方法。一旦底层的表有变化,不用去修改嵌入到应用程序中的sql代码,只要修改存储过程就可以了。
6、存储过程的查询响应时间比较稳定。存储过程提供了更加可靠的查询计划缓存,因此可以重用,而即席查询完全依赖于执行计划被缓存的环境(语句中的参数)。
另外,需要注意的:'CREATE/ALTER PROCEDURE'不允许将数据库名称指定为对象名前缀
--1.1创建无参数存储过程 --这个存储过程的定义很像视图定义 create procedure dbo.usp_wct as  select wcId,        wcV,        wcDate from wcT go  --1.2执行存储过程 exec dbo.usp_wct    --2.1创建带参数的存储过程 create procedure dbo.usp_param_wct (@wcId bigint =1,        --默认值为1  @wcDate datetime =null) --默认值为null as  select wcV from dbo.wcT where wcId = @wcId       and isnull(@wcDate,1)=case when @wcdate is null                                       then 1                                   else wcDate                             end  --返回状态值,一般不用于返回计算结果,而是用来返回表明存储过程执行的状态       return 1   go   --2.2.1调用存储过程 exec dbo.usp_param_wct '1','2012-07-01'  --2.2.2调用存储过程,带参数名 exec dbo.usp_param_wct @wcid='1',                        @wcdate='2012-07-01'  --2.2.3调用存储过程,带参数名,只输入一个参数值,另一个会使用默认值 exec dbo.usp_param_wct @wcid='1'  --2.2.4调用存储过程,带参数名,不输入参数,2个参数都会使用默认值 exec dbo.usp_param_wct     --3.1创建带output参数的存储过程 create procedure dbo.usp_output_param_wct (@wcId bigint =1,            --默认值为1  @wcDate datetime =null,     --默认值为null  @wcV varchar(50) output)    --输出参数,用来返回计算结果 as  select @wcV = wcV from dbo.wcT where wcId = @wcId       and isnull(@wcDate,1)=case when @wcdate is null                                       then 1                                   else wcDate                             end  --返回状态值,一般不用于返回计算结果,而是用来返回表明存储过程执行的状态       return 1   go   --3.2调用存储过程 declare @output varchar(50)  exec dbo.usp_output_param_wct @wcId =1,         --输入参数                               --@wcDate = null,                               @wcv = @output output       --输出参数,存放返回值  print @output      --4.1修改存储过程 create procedure dbo.usp_output_param_wct (@wcId bigint =1,            --默认值为1  @wcDate datetime =null,     --默认值为null  @wcV varchar(50) output)    --输出参数,用来返回计算结果 with encryption --加密存储过程 as  select @wcV = wcV from dbo.wcT where wcId = @wcId       and isnull(@wcDate,1)=case when @wcdate is null                                       then 1                                   else wcDate                             end  --返回状态值,一般不用于返回计算结果,而是用来返回表明存储过程执行的状态       return 1   go        --4.2查看定义 select object_name(object_id),        definition                --显示为NULL from sys.sql_modules where object_id = object_id('dbo.usp_output_param_wct')     --5.在SQL Server启动时自动执行存储过程 create procedure dbo.create_table   as    select * into wc.dbo.wcX    from wc.dbo.wcT go  --5.1设置为true,在SQL Server启动时自动执行存储过程 exec sp_procoption @procname   = 'dbo.create_table',                    @optionname = 'startup',                    @optionvalue= 'true'                     --5.2设置为false来禁止 --只有dbo拥有的master数据库中的对象才能更改启动设置。 use master go  exec sp_procoption @procname   = 'dbo.create_table',                    @optionname = 'startup',                    @optionvalue= 'false'    --6.1每次存储过程执行时都重新编译 --需要注意的是:当表、索引数据大量更新时,会进行语句级别的重新编译 create procedure dbo.usp_backupset_info (@startDate datetime,  @finishDate datetime) with recompile     --不保存执行计划,每次都是重新编译 as  select SUM(backup_size)/1024/1024/1024 as 'GB' from msdb.dbo.backupset where backup_start_date >= @startDate       and backup_finish_date <= @finishDate       and type = 'D'  --数据库备份,不是日志备份或差异备份 go   --6.2清空过程缓存 select * from sys.dm_exec_cached_plans  dbcc freeproccache      --清空过程缓存  --再次查询发现都已经清空 select * from sys.dm_exec_cached_plans    --7.刷新存储过程,查看元数据 exec sp_refreshsqlmodule @name ='dbo.usp_output_param_wct'  select p.name,           --存储过程名称        p.object_id,                pp.parameter_id,           pp.name,          --参数名称        pp.default_value, --好像不起作用        t.name            --参数列的类型 from sys.procedures p inner join sys.parameters pp         on pp.object_id = p.object_id inner join sys.types t         on t.system_type_id = pp.system_type_id where p.object_id =965578478   --8.删除存储过程 DROP PROCEDURE dbo.usp_output_param_wct
存储过程的Execute as选项

--1.创建表 create table dbo.wcE 	(vid int not null primary key clustered, 	 v int not null 	)  insert into dbo.wcE values(1,100),       (2,200),       (3,300)   --2.创建存储过程,存储过程的架构与存储过程中引用对象的架构一样 create procedure dbo.usp_delete_wcE as  delete from dbo.wcE go   --3.1创建登录名 create login wclogin with password = 'wclogin123'   --3.2创建数据库用户 create user wclogin    --4.授予用户执行存储过程的权限 grant exec on dbo.usp_delete_wcE to wclogin	  grant connect  to wclogin    /*==================================================== 5.1打开另一个客户端,以wclogin登录名登进去,然后执行存储过程, 虽然这个用户没有访问存储过程中所引用表的权限, 但是由于存储过程的架构与存储过程中引用对象的架构一样, 同时由于存储过程中只能是insert,update,delete,select, 而不能是trancate等操作,这就是所有权链,所以没有报错.  特别需要注意的是:以上的所有权链对于动态的SQL是无效的. ======================================================*/ exec dbo.usp_delete_wcE  --5.2这里改为truncate后,会报错 alter procedure dbo.usp_delete_wcE as  truncate table dbo.wcE go    --6.1使用execute as owner指定存储过程的任何调用, --都是在存储过程架构的拥有者的安全上下文运行的 --这时再次以wclogin登录就可以执行存储过程而不会报错 alter procedure dbo.usp_delete_wcE with execute as owner as  truncate table dbo.wcE go   --6.2以执行用户的权限来执行存储过程 --在以wclogin登录执行时会报错 alter procedure dbo.usp_delete_wcE with execute as caller as  truncate table dbo.wcE go  --6.3以创建或最近一次更新存储过程的用户的权限来执行存储过程, --在以wclogin登录执行时会报错 alter procedure dbo.usp_delete_wcE with execute as self as  truncate table dbo.wcE go   --6.4以指定的用户的权限来执行存储过程, --在以wclogin登录执行时显然不会报错 alter procedure dbo.usp_delete_wcE with execute as 'dbo' as  truncate table dbo.wcE go    --6.5这个存储过程用了动态的SQL语句 create procedure dbo.w as  exec('select * from dbo.wcE'); go  grant exec on dbo.w to wclogin   --在客户端以wclogin登录,执行时会报错 --拒绝了对对象'wcE'(数据库'wc',架构'dbo')的SELECT权限。 exec dbo.w


--1.函数 if exists(select * from sys.objects where name = 'f_splitSTR' and type = 'tf')    drop function dbo.f_splitSTR go  create function dbo.f_splitSTR ( 	@s varchar(8000),     --要分拆的字符串 	@split varchar(10)    --分隔字符 )  returns @re table(                      --要返回的临时表                      col varchar(1000)  --临时表中的列                   ) as begin      declare @len int      set @len = LEN(@split)      --分隔符不一定就是一个字符,可能是2个字符      while CHARINDEX(@split,@s) >0   begin 	insert into @re  	values(left(@s,charindex(@split,@s) - 1)) 	 	set @s = STUFF(@s,1,charindex(@split,@s) - 1 + @len ,'')    --覆盖:字符串以及分隔符   end      insert into @re values(@s)      return   --返回临时表 end go     select * from dbo.f_splitSTR('123,456',',')    --2.存储过程  --创建类型 create type var_orgid as table ( org_id numeric(10,0) )  --创建存储过程 create proc usp_orgid @orgid_table var_orgid readonly as  select * from @orgid_table go   --定义表变量 declare @orgid_table as var_orgid  insert into @orgid_table  values(123)  exec usp_orgid @orgid_table

sp_executesql存储过程,可以使动态语句重用,提高效率:

DECLARE @sumcount INT DECLARE @tmpSQL NVARCHAR(1000) DECLARE @TABLENAME  VARCHAR(50) SELECT @TABLENAME = ' sys.objects ' --表名变量赋值  SELECT @tmpSQL = 'select @sum = convert(varchar(50),count(object_id)) from ' + @TABLENAME    /* 参数1: 动态语句 参数2:定义的参数,这个参数就是在动态语句中引用到的变量@sum 参数3:指明了执行结果@sum的值,放到@sumcount参数里面,  这里需要特别注意的是,动态语句中的变量,和外面定义的变量,是不同的, 下面的语句,实际相当于:  declare @sum int   select @sum = convert(varchar(50),count(object_id))  from  + 表名   所以,通过sp_executesql,可以把语句产生的结果输出到外面的变量, 这样我们才能知道输结果 */ exec sp_executesql @tmpsql,                    N'@sum int output',                    @sumcount out  select @sumcount

try catch 错误处理

create proc proc_t(@i int) as  select 5 * 1.0 / @i go   --1.不会报错 begin try 	begin tran 		exec proc_t 1 		select '执行成功' 	commit tran end try begin catch   select '执行失败'   if @@trancount >0       rollback end catch   --2.这次会报错,因为分母为0 begin try 	begin tran 		exec proc_t 0 		select '执行成功' 	commit tran end try begin catch   select '执行失败'   if @@trancount >0       rollback end catch


本文出自 “探索SQLServer” 博客,请务必保留此出处http://yupeigu.blog.51cto.com/3323001/1368094
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: