sp_executesql和exec使用注意事项

      一.使用注意

       当 sp_executesql 或 EXECUTE 语句执行字符串时,字符串将作为它的自包含批处理执行。SQL Server 会将字符串中的一个或多个 Transact-SQL 语句编译为独立于批处理(包含 sp_executesql 或 EXECUTE 语句)执行计划的执行计划。下列规则适用于自包含批处理:

  • 在执行 sp_executesql 或 EXECUTE 语句之前,不会将 sp_executesql 或 EXECUTE 字符串中的 Transact-SQL 语句编译到执行计划中。执行字符串之前,不会分析或检查其错误。执行时才对字符串中引用的名称进行解析。 

View Code
1 DECLARE @CharVariable CHAR(3);
2  SET @CharVariable = 'abc';
3  --print还是可以执行输出
4  print @CharVariable
5  EXECUTE ('there is a error')
6  GO
  • 已执行的字符串中的 Transact-SQL 语句不能访问包含 sp_executesql 或 EXECUTE 语句的批处理中声明的任何变量。包含 sp_executesql 或 EXECUTE 语句的批处理不能访问已执行字符串中定义的变量或局部游标。

View Code
1 /*Show not having access to variables from the calling batch. */
2  DECLARE @CharVariable CHAR(3);
3  SET @CharVariable = 'abc';
4  /* sp_executesql fails because @CharVariable has gone out of scope. */
5 EXECUTE sp_executesql N'PRINT @CharVariable';
6 GO
  • 如果已执行字符串包含一个更改数据库上下文的 USE 语句,则对数据库上下文所做的更改将仅持续到 sp_executesql 或 EXECUTE 语句运行结束。

View Code
1 /* Show database context resetting after sp_executesql finishes. */
2 USE master;
3 GO
4 EXECUTE sp_executesql N'USE AdventureWorks2008R2;'
5 GO
6 /* This statement fails because the database context
7 has now returned to master. */
8 SELECT * FROM Sales.Store;
9 GO

      

       二.sp_executesql和exec的区别

      sp_executesql 支持替换 Transact-SQL 字符串中指定的任何参数值,但 EXECUTE 语句不支持。因此,由 sp_executesql 生成的 Transact-SQL 字符串比那些由 EXECUTE 语句生成的字符串更加相似。SQL Server 查询优化器可能将 sp_executesql 的 Transact-SQL 语句与以前所执行的语句的执行计划相匹配,从而节省编译新的执行计划的开销。

      EXECUTE 语句:所有参数值都必须转换为字符或 Unicode,并成为 Transact-SQL 字符串的一部分。如果重复执行语句,则即使只有提供的参数值不同,每次执行时也必须生成全新的 Transact-SQL 字符串。这样就会以下列方式生成额外的开销:

  • 不断更改字符串文本(特别是复杂 Transact-SQL 语句)中的参数值,会影响 SQL Server 查询优化器将新的 Transact-SQL 字符串与现有执行计划相匹配的功能。

  • 每次执行时均必须重新生成整个字符串。

  • 每次执行时必须将参数值(非字符或 Unicode 值)转换为字符或 Unicode 格式。

      sp_executesql语句:

      1.因为 Transact-SQL 语句的实际文本在两次执行之间未更改,所以查询优化器能够将第二次执行中的 Transact-SQL 语句与第一次执行时生成的执行计划相匹配。因此,SQL Server 不必编译第二条语句。

      2.Transact-SQL 字符串只生成一次。

      3.整型参数按其本身格式指定。不需要转换为 Unicode。

      4.sp_executesql还可以使用output参数

        sp_executesql:可以使用参数,如果直接使用Exec(@sqlStr2)则会提示没有声明标量@age,就算是在@sqlStr2之前就声明@age也是会出错的。

      

View Code
1 DECLARE @sqlStr2 NVARCHAR(500)
2 SET @sqlStr2=N'select * from person where age=@age'
3 DECLARE @paratype NVARCHAR(50)
4 DECLARE @ageInt NVARCHAR(20)
5 SET @paratype=N'@age int'
6 SET @ageInt=11
7 EXEC sys.sp_executesql @sqlStr2,@paratype,@age=@ageInt

       sp_executesql:可以使用OutPut参数 

View Code
1 DECLARE @sqlStr4 NVARCHAR(500)
2 SET @sqlStr4 = N'select @num=count(*) from person where age=@age'
3 DECLARE @paratype NVARCHAR(50)
4 DECLARE @num INT
5 DECLARE @age INT
6 SET @paratype = N'@num int output,@age int'
7 SET @age = 100
8 EXECUTE sys.sp_executesql @sqlStr4, @paratype, @num = @num OUTPUT, @age = @age
9 PRINT @num

      但是如果是以表名和字段名称作为sp_executesql的参数变量,也是会出现要先声明标量的错误

View Code
1 --提示为生命标量@tablename
2 DECLARE @sql NVARCHAR(500)
3 SET @sql = N'select @fieldname from @tablename'
4 DECLARE @fielaname NVARCHAR(50)
5 DECLARE @tablename NVARCHAR(50)
6 DECLARE @paratype NVARCHAR(100)
7 SET @paratype = N'@fieldname nvarchar(50),@tablename nvarchar(50)'
8 SET @fielaname = 'name'
9 SET @tablename = 'person'
10 EXECUTE sys.sp_executesql @sql, @paratype, @fielaname, @tablename
View Code
1 --查询的结果都是age
2 DECLARE @sql NVARCHAR(500)
3 SET @sql = N'select @fieldname from person'
4 DECLARE @fielaname NVARCHAR(50)
5 DECLARE @tablename NVARCHAR(50)
6 DECLARE @paratype NVARCHAR(100)
7 SET @paratype = N'@fieldname nvarchar(50)'
8 SET @fielaname = 'age'
9 SET @tablename = 'person'
10 PRINT @sql
11 EXECUTE sys.sp_executesql @sql, @paratype, @fielaname

posted @ 2011-05-05 11:21  雁北飞  阅读(662)  评论(1编辑  收藏  举报