【问题标题】:sp_executesql throws error but simple EXEC() workssp_executesql 抛出错误,但简单的 EXEC() 有效
【发布时间】:2017-05-09 02:02:11
【问题描述】:

我需要以动态方式创建用户定义类型,但是

exec() 方式:

-- This works
DECLARE @column NVARCHAR(MAX) = 'Id INT'
EXEC ('CREATE TYPE dbo.MyDataType AS TABLE ('+ @column +')')

sp_executesql 方式:

-- This does not work
DECLARE @column NVARCHAR(MAX) = 'Id INT'
EXECUTE sp_executesql N'CREATE TYPE dbo.MyDataType AS TABLE ( @column )', @column;  

错误:

消息 102,第 15 级,状态 1,第 1 行
“Id”附近的语法不正确。

消息 102,第 15 级,状态 1,第 1 行
'@column' 附近的语法不正确。

我错过了什么?

【问题讨论】:

  • 不能用参数指定列名。您需要为此执行动态 SQL。表名和任何 SQL 对象名也是如此。

标签: sql-server-2008 dynamic-sql sp-executesql


【解决方案1】:

即使采用sp_executesql 方法,您也需要使用动态 SQL:

DECLARE @column NVARCHAR(MAX) = N'Id INT'
DECLARE @sql NVARCHAR(MAX)
SET @sql = 'CREATE TYPE dbo.MyDataType AS TABLE ( ' + @column + ')'
EXECUTE sp_executesql @sql

您可以将参数定义和值传递到sp_executesql,如下所示:

DECLARE @IntVariable int;  
DECLARE @SQLString nvarchar(500);  
DECLARE @ParmDefinition nvarchar(500);  

/* Build the SQL string one time.*/  
SET @SQLString =  
     N'SELECT BusinessEntityID, NationalIDNumber, JobTitle, LoginID  
       FROM AdventureWorks2012.HumanResources.Employee   
       WHERE BusinessEntityID = @BusinessEntityID';  
SET @ParmDefinition = N'@BusinessEntityID tinyint';  

/* Execute the string with the first parameter value. */  
SET @IntVariable = 197;  
EXECUTE sp_executesql @SQLString, @ParmDefinition,  
                      @BusinessEntityID = @IntVariable;  

/* Execute the same string with the second parameter value. */  
SET @IntVariable = 109;  
EXECUTE sp_executesql @SQLString, @ParmDefinition,  
                      @BusinessEntityID = @IntVariable; 

(来自MSDN pagesp_executesql

但我认为这不适合您的用例。

【讨论】:

  • 列名最好使用QUOTENAME。
  • 你的例子和我的例子的主要区别是什么?因为我用这种方式尝试过同样的错误。
  • @Muflix 道歉,看起来您无法在对 sp_executesql 的调用中直接连接字符串 - 我已经编辑了我的答案以反映这一点并这次测试了结果。
  • @TT。你到底是什么意思?设置@column 值时?喜欢DECLARE @column NVARCHAR(MAX) = QUOTENAME('Id') + ' INT'
  • @3N1Gm4 感谢您的回答,它现在可以工作了,但是在这种方法中,当 exec() 函数省略变量参数时,它有什么好处吗?我认为它可能允许 sql 注入,因为它不知道 @SQLString 变量中必须包含什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-01-25
  • 1970-01-01
  • 2013-01-07
  • 1970-01-01
  • 2010-11-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多