鉴于下表:
USE tempdb;
CREATE TABLE #T(Val INT);
INSERT INTO #T VALUES (1), (2), (3), (4), (5);
我希望在给定EXEC
值的情况下使用Val
执行动态sql查询:
DECLARE @sql NVARCHAR(MAX);
DECLARE @Val INT = 3;
EXEC ('SELECT * FROM #T WHERE Val = ' + @Val);
执行时没有错误,并给出正确的结果。
我的假设是这会产生错误:
转换varchar值' SELECT * FROM #T时转换失败 Val ='数据类型int。
由于@Val
属于INT
数据类型,并且data type precedence的规则,EXEC
内的查询必须转换为INT
。< / p>
我的问题是为什么调用EXEC
产生转换错误?
注意:
- 我知道sp_executesql
。我也没有要求替代方案。我只是要求解释为什么没有产生错误。
- 此question的答案似乎无法解释我的情况,因为问题涉及VARCHAR
到VARCHAR
串联。
答案 0 :(得分:6)
根据MSDN/BOL,EXEC[UTE]
语句的简化语法为:
Execute a character string
{ EXEC | EXECUTE }
( { @string_variable | [ N ]'tsql_string' } [ + ...n ] )
[ AS { USER } = ' name ' ]
[;]
@string_variable
Is the name of a local variable. @string_variable can be any char, varchar, nchar, or nvarchar data type. These include the (max) data types.
很少注意到:
1)根据这一行( { @string_variable | [ N ] 'command_string [ ? ]' } [ **+** ...n ]
,我们可以编写类似EXEC (@var1 + @var2 + @var3)
的内容,但根据最后一段,SQL Server希望这些变量具有以下 string 数据类型:char
,varchar
,nchar
或nvarchar
。
2)此外,此语法仅引用string variables
(@string_variable | [ N ] 'command_string [ ? ]' } [ + ...n
)。我认为这就是EXEC ('SELECT * FROM #T WHERE Val = ' + 3);
失败的原因:3
不是变量。
3)我假设当其中一个变量没有上述字符串类型之一时,SQL Server将进行隐式转换。我假设它会从INT
(例如)的源变量转换为NVARCHAR
,因为它在这些字符串类型之间具有最高data type precedence。
4)这不是data type precedence不起作用的唯一地方。 ISNULL(param1, param2)
这只是另一个例子。在这种情况下,param2
将转换为param1
的数据类型。
答案 1 :(得分:0)
允许从int
到字符串类型的隐式转换,至少可以追溯到SQL Server 2008.
参考:Data Type Conversion (Database Engine)
您无法停用隐式转化:Is there a way to turn off implicit type conversion in SQL Server?
编辑:我最初写的
'SELECT * FROM #T WHERE Val = ' + @Val
是在调用EXEC
之前创建的。
我对此不太确定。我现在怀疑EXEC
的参数被传递给数据库引擎的一部分,它以与我们以前看到的不同的方式解析它。
答案 2 :(得分:0)
所有MSDN告诉EXEC [UTE]的结论是:
连接在SQL Server解析器中以逻辑方式执行,从不在内存中实现。
所以我们不太了解SQL Server内部的内容。我们所知道的是,EXEC不接受表达式作为参数,而是接受由&#39; +&#39;分隔的字符串列表。
如果你看一下语法:
Execute a character string
{ EXEC | EXECUTE }
( { @string_variable | [ N ]'tsql_string' } [ + ...n ] )
[ AS { LOGIN | USER } = ' name ' ]
[;]
它直接支持由&#39; +&#39;分隔的多个字符串或变量。字符。因此,您实际上并没有将表达式传递给EXEC,因此您绕过了SQL Server表达式解析器。