【网学网提醒】:网学会员,鉴于大家对动态语句语法exec和sp_executesql语法的区别十分关注,会员在此为大家搜集整理了“动态语句语法exec和sp_executesql语法的区别”一文,供大家参考学习!
动态语句语法:
--方法1查询表改为动态
select*fromsysobjects
exec('selectID,Namefromsysobjects')
execsp_executesqlN'selectID,Namefromsysobjects'--多了一个N为unicode
--方法2:字段名,表名,数据库名之类作为变量时,用动态SQL
declare@FNamevarchar(20)
set@FName='ID'
exec('select'+@FName+'fromsysobjectswhere'+@FName+'=5')
declare@svarchar(1000)
set@s=N'select'+@FName+'fromsysobjectswhere'+@FName+'=5'
execsp_executesql@s--会报错
declare@snvarchar(1000)--改为nvarchar
set@s=N'select'+@FName+'fromsysobjectswhere'+@FName+'=5'
execsp_executesql@s--成功
--方法3:输入参数
declare@iint,@snvarchar(1000)
set@i=5
exec('selectID,NamefromsysobjectswhereID='+@i)
set@s='selectID,NamefromsysobjectswhereID=@i'
execsp_executesql@s,N'@iint',@i--此处输入参数要加上N
--方法4:输出参数
declare@iint,@snvarchar(1000)
set@s='select@i=count(1)fromsysobjects'
--用exec
exec('declare@iint'+@s+'select@i')--把整个语句用字符串加起来执行
--用sp_executesql
execsp_executesql@s,N'@iintoutput',@ioutput--此处输出参数要加上N
select@i
--方法5:输入输出
--用sp_executesql
declare@iint,@conint,@snvarchar(1000)
set@i=5
select@s='select@con=count(1)fromsysobjectswhereID>@i'
execsp_executesql@s,N'@conintoutput,@iint',@conoutput,@i
select@con
--用exec
declare@iint,@snvarchar(1000)
set@i=5
select@s='declare@conintselect@con=count(1)fromsysobjectswhereID>'+rtrim(@i)+'select@con'
exec(@s)
1、EXEC命令的括号中只允许包含一个字符串变量,或者一个字符串文本,或者字符串变量与字符串文本的串联。不能再括号中使用函数或CASE表达式,如下面尝试在括号中调用QUOTENAME函数以引用对象名称,运行将失败:
1:DECLARE@schemanameNVARCHAR(255),@tablenameNVARCHAR(128)
2:SET@schemaname='dbo'
3:SET@tablename='OrderDetails'
4:
5:EXEC(N'SELECTCOUNT(*)FROM'+QUOTENAME(@schemaname)+N'.'+QUOTENAME(@tablename)+N';')
上述代码将会产生如下错误:
消息102,级别15,状态1,第5行
'QUOTENAME'附近有语法错误。
SQLServer分析和编译时间:
CPU时间=0毫秒,占用时间=0毫秒。
SQLServer执行时间:
CPU时间=0毫秒,占用时间=0毫秒。
所以做好的方法是把代码构造到一个变量中,这样就不会受限制了,然后再把该变量作为EXEC命令的输入参数,就像这样:
1:DECLARE@schemanameNVARCHAR(255),
2:@tablenameNVARCHAR(128),
3:@sqlNVARCHAR(MAX)
4:SET@schemaname='dbo'
5:SET@tablename='OrderDetails'
6:SET@sql=N'SELECTCOUNT(*)FROM'+QUOTENAME(@schemaname)+N'.'
7:+QUOTENAME(@tablename)+N';'
8:EXEC(@sql)
2、EXEC不提供接口。EXEC(
ring>)不提供接口。它唯一的输入就是包含你要调用代码的字符串。动态批处理不能访问在调用批处理中定义的局部变量。如下面代码尝试访问定义在调用批处理中的变量将失败。
1:DECLARE@iINT
2:SET@i=10248
3:
4:DECLARE@sqlNVARCHAR(MAX)
5:
6:SET@sql='SELECT*FROMdbo.OrdersWHEREOrderID=@i;'
7:EXEC(@sql)
将产生如下错误:
消息137,级别15,状态2,第1行
必须声明标量变量"@i"。
使用EXEC时,如果想访问变量,必须把变量内容串联到动态构建的代码字符串中。
DECLARE@iINT
SET@i=10248
DECLARE@sqlNVARCHAR(MAX)
SET@sql='SELECT*FROMdbo.OrdersWHEREOrderID='
+CAST(@iASNVARCHAR(10))+';'
EXEC(@sql)
这样就没有问题了。
如果一个变量包含字符串,把该变量的内容串联到代码将会导致安全风险(SQL注入),为了避免SQL注入,可以吧字符串大小限制为所需的最小长度。当然,实际中这种情况根本不需要动态SQL直接执行SQL语句就可以,这个示例只是为了演示。
串联变量的内容存在性能方面的弊端,SQLServer将为每个唯一的查询字符串创建新的即席执行计划,即使查询模式相同也是这样的。为演示这一点,先清空缓存中的执行计划。
DBCCFREEPROCCACHE
将上端代码执行三次,分别为@i赋值10248,10249和10250,然后使用下面的代码查询
1:SELECTcacheobjtype,
2:objtype,
3:usecounts,
4:sql
5:FROMsys.syscacheobjects
6:WHEREsqlNOTLIKE'%cache%'
7:ANDsqlNOTLIKE'%sys.%'
得到查询结果:
cacheobjtypeobjtypeusecountssql
CompiledPlanAdhoc1SELECT*FROMdbo.OrdersWHEREOrderID=10250;
CompiledPlanAdhoc1SELECT*FROMdbo.OrdersWHEREOrderID=10248;
CompiledPlanPrepared3(@1smallint)SELECT*FROM[dbo].[Orders]WHERE[OrderID]=@1
CompiledPlanAdhoc4SETSTATISTICSIOONSETSTATISTICSTIMEON
CompiledPlanAdhoc1SELECT*FROMdbo.OrdersWHEREOrderID=10249;
CompiledPlanAdhoc4SETSTATISTICSIOOFFSETSTATISTICSTIMEOFF
EXEC除了不支持动态批处理中的输入参数外,也不支持输出参数。默认情况下,EXEC把查询输出返回给调用者。如果你想把输出结果返回给调用批处理中的变量,事情就没那么简单了,为此,你需要使用INSERTEXEC把输出插入到一个目的表,然后再从该表中取值,赋给该变量,就像这样:
1:DECLARE@schemanameNVARCHAR(128),
2:@tablenameNVARCHAR(128),
3:@colnameNVARCHAR(128),
4:@sqlNVARCHAR(MAX),
5:@cntINT
6:
7:SET@schemaname='dbo'
8:SET@tablename='Orders'
9:SET@colname='CustomerID'
10:
11:SET@sql
=N'SELECTCOUNT(DISTINCT'+QUOTENAME(@colname)+')FROM'
12:+QUOTENAME(@schemaname)+N'.'+QUOTENAME(@tablename)+N';'
13:
14:CREATETABLE#T1(cntINT)
15:INSERTINTO#T1
16:EXEC(@sql
17:)
18:SELECT@cnt=cnt
19:FROM#T1
20:SELECT@cnt
21:DROPTABLE#T1
3、在SQLServer2000中串联变量值时,EXEC比sp_executesql多一个优势,它支持更长的代码,尽管技术上sp_executesql的输入代码字符串是NTEXT类型的,但你一般是在局部变量中构造代码字符串。而你又不能用大型对象类型声明局部变量,所以,实际上在sp_executesql中执行的查询字符串被限制为Unicode字符串(NVARCHAR)支持的最大长度4000,而EXEC支持常规字符串(VARCHAR)允许最大8000个字符。另外EXEC还支持一个特殊的功能,它允许你在括号中串联多个变量,每个变量都支持8000个字符的长度。
在SQLServer2005中,就不用这么纠结了,因为可以为EXEC命令提供一个VARCHAR(MAX)或NVARCHAR(MAX)的变量作为输入,输入字符串可以达到2GB大小