在EXEC中连接INT和VARCHAR不会产生转换错误

时间:2016-06-16 07:29:32

标签: sql-server dynamic-sql

鉴于下表:

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的答案似乎无法解释我的情况,因为问题涉及VARCHARVARCHAR串联。

3 个答案:

答案 0 :(得分:6)

根据MSDN/BOLEXEC[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 数据类型:charvarcharncharnvarchar

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表达式解析器。