在SQL Server中的exec()外部声明的exec()中设置变量

时间:2017-02-20 22:06:06

标签: sql sql-server dynamic-sql

有人可以解释为什么这不起作用:

DECLARE @PROCESS_TABLE varchar(100) = 'Table Name'
DECLARE @SRIDCount int
EXEC('SELECT ' + @SRIDCount + ' = COUNT(DISTINCT Geom.STSrid) FROM ' + @PROCESS_TABLE + '')
Print @SRIDCount

Incorrect syntax near '='.

但这样做:

DECLARE @PROCESS_TABLE varchar(100) = 'Table Name'
DECLARE @SRIDCount int
DECLARE @SQLString nvarchar(max)

SET @SQLString = 'SELECT @SRIDCount = COUNT(DISTINCT Geom.STSrid) FROM ' + @PROCESS_TABLE + ''
EXECUTE SP_executesql @SQLString, N'@SRIDCount int OUTPUT', @SRIDCount = @SRIDCount OUTPUT
Print @SRIDCount

1

大多数情况下,我想了解为什么我不能在exec()中设置变量。通过比较使用SP_executesql似乎很麻烦和复杂,到目前为止我已经没有使用它了。

4 个答案:

答案 0 :(得分:1)

首先,请尽量避免使用动态sql。想想sql注入,可读性,错误处理,可维护性......有很多理由可以避免动态sql。我声称可以在不使用动态sql的情况下解决上述用例。

接下来,您需要了解'SELECT ' + @SRIDCount正在尝试将@SRIDCount(即NULL btw)的值添加到前导varchar,而不是变量的名称。您可以通过将变量添加到查询字符串来轻松修复:SELECT @SRIDCount = COUNT(DISTINCT Geom.STSrid)...

您的第二个错误是假设EXEC()可以干扰内部批处理之外的变量,这些变量被视为自己的事务,并且无法访问您声明的变量。

使用SP_executesql提供的示例也是一个封闭的事务,通过指定您可以使用查询结果的输出。

如果您将变量包含在:

中,则重写您的第一个查询将起作用
DECLARE @PROCESS_TABLE VARCHAR(100) = QUOTENAME('Table Name')
EXEC(N'DECLARE @SRIDCount INT
SELECT @SRIDCount = COUNT(DISTINCT Geom.STSrid) 
FROM ' + @PROCESS_TABLE + '
PRINT @SRIDCount')

但我假设你想在另一个查询中使用count。因此,下面的解决方法应该完成这项工作:

DECLARE @PROCESS_TABLE VARCHAR(100) = 'Table Name'
DECLARE @SRID TABLE (SRIDCount int)
DECLARE @SRIDCount INT

INSERT @SRID
INSERT INTO @SRID
EXEC(N'SELECT COUNT(DISTINCT Geom.STSrid) 
FROM ' + @PROCESS_TABLE )

SELECT @SRIDCount = SRIDCount 
FROM @SRID

但是,就像我在开始时所说的那样,重新思考一下你试图实现什么以及如何在没有动态sql的情况下实现它。

答案 1 :(得分:0)

它不起作用,因为exec在一个批处理中运行你的sql命令,并且变量不存在于它自己的批处理之外。

execute

  

在Transact-SQL中执行命令字符串或字符串   批次...

variable scope

  

变量的范围是Transact-SQL语句的范围   可以引用变量。变量的范围持续时间   指出它是在批处理或存储过程结束之前声明的   它被声明...

答案 2 :(得分:0)

请注意您(必须)使@SRIDCount与查询一起工作的不同之处:

'SELECT ' + @SRIDCount + ' = COUNT....'会将字符串SELECT @SRIDCount'COUNT ...' VALUE 连接起来。 由于变量是新实例化的,因此您最有可能最终得到一行:

'SELECT 0 = COUNT ...

另一方面,后面的示例是一个仍然包含变量 NAME 的字符串,而不是 VALUE ,因此这个字符串按预期工作。这,但不仅,因为

N'@SRIDCount int OUTPUT'

您明确将此变量标记为要从查询返回的某个值。

答案 3 :(得分:0)

DECLARE @PROCESS_TABLE varchar(100) = 'Table Name'
DECLARE @SRIDCount int
EXEC('SELECT ' + @SRIDCount + ' = COUNT(DISTINCT Geom.STSrid) FROM ' + @PROCESS_TABLE + '')
Print @SRIDCount

Incorrect syntax near '='.
  1. 由于您尚未为SRIDCount分配值,因此该语句实际上是

    'SELECT ' + NULL + ' = Count(...'

  2. 连接字符串和null会产生Null。你本质上是试图运行

  3. Exec (null);

    1. 如果要为SRIDCount分配值,则会收到数据类型转换错误,因为无法将数字添加到字符串(string + int + string)。如果将SRIDCount转换为字符数据类型,则可以在字符串中正确替换。但是,这不太可能是你想要做的。

    2. Exec在新批处理中运行查询。批处理之间不共享内存,Exec语句中的批处理对外部语句没有可见性。

    3. 在执行之前尝试打印@SRIDCount。一旦打印的语句看起来很好,添加Execute语句并再次运行。如果在验证语句之前包含Exec,则可能会运行不符合预期的查询。