zoukankan      html  css  js  c++  java
  • 【SQL Server学习笔记】存储过程、sp_executesql存储过程、try catch错误处理

    存储过程就是把一个或多个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
    
  • 相关阅读:
    SoapUI 使用笔记
    git 使用笔记(二)
    git 使用笔记(一)
    jquery 拓展
    hdu 1024 Max Sum Plus Plus (DP)
    hdu 2602 Bone Collector (01背包)
    hdu 1688 Sightseeing (最短路径)
    hdu 3191 How Many Paths Are There (次短路径数)
    hdu 2722 Here We Go(relians) Again (最短路径)
    hdu 1596 find the safest road (最短路径)
  • 原文地址:https://www.cnblogs.com/momogua/p/8304614.html
Copyright © 2011-2022 走看看