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
    
  • 相关阅读:
    天翼网关获取超级密码
    Wirte-up:攻防世界Web解题过程新手区01-06
    F#周报2019年第12期
    F#周报2019年第11期
    F#周报2019年第10期
    F#周报2019年第9期
    F#周报2019年第8期
    F#周报2019年第7期
    ML.NET 0.10特性简介
    F#周报2019年第6期
  • 原文地址:https://www.cnblogs.com/momogua/p/8304614.html
Copyright © 2011-2022 走看看