(2.3)DDL增强功能-流程化控制与动态sql

Posted 郭大侠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(2.3)DDL增强功能-流程化控制与动态sql相关的知识,希望对你有一定的参考价值。

 关键词:动态SQL

1.流程控制

在T-SQL中,与流程控制语句相关的关键字有8个:

 

BEGIN...END

BREAK

GOTO

CONTINUE

IF...ELSE

WHILE

RETURN

WAITFOR

 

其实还可以加一个,那就是GO,下面我们一个一个来解释说明意思吧

  (1)GO

:批处理提交语句,相当于把GO之前的所有东西都提交给系统了(平常看好像不用它也没事,但是在sqlcmd登录后dos界面使用批处理就一定要用),该销毁的销毁该回收的回收等等,演示如图

    

  GO后面还可以加数字,会重复执行。如图:

    

 

 

  (2)BEGIN ... END

    这个其实就是逻辑块,类似于各大语言的{}

  (3)while/break/continue

   

     
 while (表达式) --如果表达式成立则运行begin end中的statement语句,否则略过     begin       statement;     end


    break:直接跳出循环
    continue:本次循环后续代码不执行了,直接开始下一次循环
    太简单,就不演示了

  (4)IF ... ELSE

 

    IF (表达式) --如果表达式成立就执行BEGIN END中间的statement句子
    BEGIN
              statement;
    END    
    ELSE  --如果IF中的表达式不成立则跳到ELSE中来,执行statement1;
    BEGIN
              statement1;
    END    

    --注意:如果不写BEGIN END那么默认只有一条语句属于IF/ELSE

  (5)goto

    goto是个捣乱的家伙,可以随意跳到任意一个定义点,基本没什么用,一般用来跳到错误

    


--实现循环功能的goto 跳转
基本用法:
定义点名称:
goto 定义点名称
案例:
  declare
@n int   set @n=1   print_point:print @n   IF (@n < 3)   begin   set @n=@n+1   goto print_point   end   print \'the @n alread > 3\'

  结果如图:

    

  (6)return

      迅速结束任何一个批处理(batch),并且return后面的语句不会再执行了,演示如下

    ,发现print 5也没有执行为什么呢。记住了,批处理是以GO为结束

   (7)waitfor  

        延迟与定点

     (7.1)waitfor delay time  延迟 time(默认为秒)后继续顺序执行

        (7.2)waitfor time  time  定点到time的时候再顺序执行

      演示如下

  print 1
  waitfor delay \'00:00:05\' --注意时间格式的写法
  print 2

  print 1
  waitfor time \'16:02:05\'  --注意时间格式的写法
  print 2

 

 

2.动态SQL

其他类型必须转换成字符类型才能使用动态sql

  (1)变量定义

    declare @n int

    分析:declare: 为关键字;  @n:@为变量标识,n变量名 ;int为变量类型;

    set @n = 1 ; select @n=1

    分析:set为赋值关键字,用select 也可以赋值

    使用的话,直接用@n即可

  (2)执行动态sql

   (2.1)execute,可以简写为exec

        基本形式:exec sp   或 exec(字符串),演示如下

        

  动态sql的基本演示   

        declare @sql varchar(1000),@t int
        declare @n int
            set @n=2
            set @t=10
            set @sql = \'select \'+cast(@n as varchar)+\' where 10 =     \'+cast(@t as varchar)  --注意,这里其他类型必须转换成字符类型才能使用动态sql
        execute(@sql)--可以简写为exec

 

  代码结果如下

      

  execute的连接到另一个服务器操作

    

  这就表示在链接服务器上做操作了。

  (2.2)sp_executesql

其实是一个存储过程

    要用exec去执行它,常用形式为: exec sp_executesql  @sql ,但@sql比较为UniCode形式,演示如下

    (不知道什么是Unicode的请看https://www.cnblogs.com/gered/p/9117522.html 中第5点中的字符串类型,常量字符串在前面加个N即可,如图)

      

    sp_executesql  可以在动态SQL中做参数输入输出操作

    【1】输入

declare @sql nvarchar(1000),@num int
set @sql = N\'select @num=1\'
exec sp_executesql @sql,N\'@num int output\',@num output   --必须要在这里还要定义一次
print @num

结果:1

    【2】输入输出结合

declare @sql nvarchar(1000),@num int
set @sql = N\'select @num=1 where @num2 = 10\'
exec sp_executesql @sql,N\'@num int output,@num2 int\',@num output,@num2=10   --如果多个参数,一一对应即可
print @num

结果:1


declare @sql nvarchar(1000);
declare @num1 int;
declare @v_id int = 2 ;
declare @table_name nvarchar(100)=N\'test..test4\';
set @sql = N\'select @num=id from \'+@table_name+N\' where id=@id \';
print @v_id
exec sp_executesql @sql,N\'@num int output,@id int \',@num1 output,@id=@v_id--必须要在这里还要定义一次;
print @sql
print @num1

 

结果:

2
select @num=id from test..test4 where id=@id
2

 

 

    

判断execute与sp_executesql的好坏与区别

  行为相同:使用的语句或批处理在执行时才编译,编译后的内容作为执行计划运行

  不同行为:execute必须要把所有东西转成字符串,sp_executesql可以入参出参。

  注意事项:

    (1)数据类型转换问题,在execute中必须转换成字符型,在sp_executesql中必须使用UniCode格式

    (2)字符串边界问题:其实也就是单引号\'  问题

  举个例子,比如正常情况下

declare @str char(6)
set @str = \'a\'
select 1 where @str = \'a\'

  换成动态sql的时候

declare @str char(6),@sql varchar(1000)
set @str = \'a\'
set @sql = \'select 1 where \'\'\'+@str+\'\'\'=\'\'a\'\'\'
exec(@sql)
--单引号在使用其本身的时候要转移,即 \'\'表示为\'


再举个日期的例子,直接用要报错
  

正确代码如下:

  

 --想执行的语句 select 1 where getdate() > \'20180601\'
  declare @str datetime,@sql varchar(1000)
  set @str = \'20180601\'
 --动态sql语句
  set @sql = \'select 1 where getdate() > \'\'\'+@str+\'\'\'\'
  exec(@sql)


   (3)表变量表字段问题

--想要查询test101表中的所有内容
declare
@table_name char(30) set @table_name = \'test101\' select * from @table_name

这样报错
--想要查询test101表中的所有内容

  declare @table_name Nchar(30)
  set @table_name = N\'test101\'
  exec sp_executesql N\'select * from @table_name\',N\'@table_name char(30)\',@table_name

 

  这样也报错

    

 

  正确的打开方式如下:

    

  declare @table_name Nchar(30),@sql nvarchar(100)
  set @table_name = N\'test101\'
  set @sql = \'select * from \'+@table_name
  exec (@sql)

   

 

 

   (4) 不能再动态sql中用exec 给变量赋值,可以用sp_executesql来赋值

 

 

  (2.3)使用 SET CONCAT_NULL_YIELDS_NULL OFF 来使得  \'a\'+null  结果为  \'a\' 而不是 null

官网:https://docs.microsoft.com/zh-cn/sql/t-sql/statements/set-concat-null-yields-null-transact-sql?view=sql-server-ver15

当 SET CONCAT_NULL_YIELDS_NULL 为 ON 时,串联空值与字符串将产生 NULL 结果。 

  例如,SELECT \'abc\' + NULL 将生成 NULL

当 SET CONCAT_NULL_YIELDS_NULL 为 OFF 时,串联空值与字符串将产生字符串本身(空值作为空字符串处理)。 

  例如,SELECT \'abc\' + NULL 将生成 abc

  

 

 

如果未指定 SET CONCAT_NULL_YIELDS_NULL,则应用 CONCAT_NULL_YIELDS_NULL 数据库选项的设置。

 备注

  SET CONCAT_NULL_YIELDS_NULL 与 ALTER DATABASE 的 CONCAT_NULL_YIELDS_NULL 设置相同。

  SET CONCAT_NULL_YIELDS_NULL 的设置是在执行或运行时设置的,而不是在分析时设置的。

创建或更改索引视图、计算列上的索引、筛选索引或空间索引时,SET CONCAT_NULL_YIELDS_NULL 必须为 ON。 

如果 SET CONCAT_NULL_YIELDS_NULL 为 OFF,无法对包含计算列上的索引、筛选索引、空间索引或索引视图的表运行任何 CREATE、UPDATE、INSERT 和 DELETE 语句。 

有关计算列的索引视图和索引需要的 SET 选项设置的详细信息,请参阅 SET Statements (Transact-SQL) 中的“使用 SET 语句时的注意事项”。

如果将 CONCAT_NULL_YIELDS_NULL 设置为 OFF,则不能出现跨服务器边界的字符串串联。

要查看此设置的当前设置,请运行以下查询。

判断是否开启

DECLARE @CONCAT_SETTING VARCHAR(3)
SET  @CONCAT_SETTING = \'OFF\';  
IF ( (4096 & @@OPTIONS) = 4096 ) SET @CONCAT_SETTING = \'ON\';  
SELECT @CONCAT_SETTING AS CONCAT_NULL_YIELDS_NULL; 

 

  

 

以上是关于(2.3)DDL增强功能-流程化控制与动态sql的主要内容,如果未能解决你的问题,请参考以下文章

第八周

用SQL语句操作数据------解析

动态执行语句

T-SQL和SQL的区别

什么是T-SQL

PL/SQL开发中动态SQL的使用方法