在动态查询之外声明的变量的动态查询值中设置

Mat*_*RGX 2 sql-server t-sql

我有一个存储过程,我以这种方式进行了简化:

DECLARE @variable1 INT

DECLARE @SQL VARCHAR(MAX)

SET @SQL = '
    DECLARE @variable2 INT

    SET @variable2 = 1
    SET '+CAST(@variable1 AS VARCHAR)+' = @variable2

    SELECT @variable1 as V1, @variable2 as V2
'
EXEC(@SQL)
Run Code Online (Sandbox Code Playgroud)

但是这个脚本没有给我任何东西!我很确定这与范围有关。问题是我需要在动态查询之外声明变量。

感谢帮助 !

编辑 :

WHILE LOOP UNTIL SELECT COUNT xxx = 0
BEGIN
    DECLARE @variable1 INT

    DECLARE @SQL VARCHAR(MAX)

    SET @SQL = '
                EXEC STORE PROC WITH PARAMETER @Param1 = @variable1 (first loop @Param1 is null)

                STORE PROC RETURN A VALUE

                SET @variable1 with return value of store proc
                and use it in second loop, third loop...
    '
    EXEC(@SQL)
END
Run Code Online (Sandbox Code Playgroud)

EzL*_*zLo 6

值得一提的三件事:

  • PRINT每当您使用动态 SQL 时,始终使用来查看生成的动态 SQL。您将看到 SQL 变量实际上包含NULL.

    DECLARE @variable1 INT
    
    DECLARE @SQL VARCHAR(MAX)
    
    SET @SQL = '
        DECLARE @variable2 INT
    
        SET @variable2 = 1
        SET ' + CAST(@variable1 AS VARCHAR) + ' = @variable2
    
        SELECT @variable1 as V1, @variable2 as V2
    '
    
    PRINT(@SQL)
    
    -- EXEC(@SQL)
    
    Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

  • 动态 SQL 的原因NULL是因为您正在连接作为@variable1内容的 NULL 值。我相信你想把文字'@variable1'写成文字:

    DECLARE @variable1 INT
    
    DECLARE @SQL VARCHAR(MAX)
    
    SET @SQL = '
        DECLARE @variable2 INT
    
        SET @variable2 = 1
        SET @variable1 = @variable2
    
        SELECT @variable1 as V1, @variable2 as V2
    '
    
    PRINT(@SQL)
    
    Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

  • 无论何时使用 EXEC,都无法再访问在外部声明的范围更改和变量。所以在动态 SQL 中,您将无法读取,@variable1因为它没有在任何地方声明。如果我们执行动态 SQL:

在此处输入图片说明


您可以在动态执行中设置变量值并能够从外部读取它们的方法是通过OUTPUT选项提供参数。这将需要使用 SP sp_executesql而不是直接EXEC

DECLARE @externalVariable INT

DECLARE @SQL NVARCHAR(MAX)

SET @SQL = '
    DECLARE @variable2 INT = 1
    SET @resultVariable = @variable2'

EXEC sp_executesql
    @stmt = @SQL,
    @params = N'@resultVariable INT OUTPUT',    -- Declare the "input" parameters for the dynamic SQL
    @resultVariable = @externalVariable OUTPUT  -- Supply the "input" parameters for the dynamic SQL

SELECT 
    Result = @externalVariable -- Read the updated value
Run Code Online (Sandbox Code Playgroud)

请注意,我将数据类型更改为NVARCHAR因为sp_executesql适用于 unicode 输入。

另一个带有更多参数的示例:

DECLARE @firstNumber INT = 15
DECLARE @secondNumber INT = 3
DECLARE @result INT

DECLARE @SQL NVARCHAR(MAX) = '
    SET @multiplicationResult = @inputFactor1 * @inputFactor2'

EXEC sp_executesql
    @stmt = @SQL,
    @params = N'
        @multiplicationResult INT OUTPUT,
        @inputFactor1 INT,
        @inputFactor2 INT',
    @multiplicationResult = @result OUTPUT,
    @inputFactor1 = @firstNumber,
    @inputFactor2 = @secondNumber

SELECT 
    Result = @result -- 45!
Run Code Online (Sandbox Code Playgroud)

如果您不必从变量读回结果,则可以通过将变量值直接“硬编码”到脚本中来构建动态 SQL。确保在脚本中正确使用数据类型转换以及转义NULL和文字值:

DECLARE @DateVariable DATETIME = GETDATE()
DECLARE @StringVariable VARCHAR(100) = NULL
DECLARE @FloatVariable FLOAT = 15.14

DECLARE @DynamicSQL VARCHAR(MAX) = '
    SELECT
        DateVariableContents = CONVERT(DATETIME, ''' + ISNULL(CONVERT(VARCHAR(100), @DateVariable), '') + '''),
        StringVariableContents = ' + ISNULL('''' + @StringVariable + '''', '''''') + ',
        FloatVariableContents = CONVERT(FLOAT, ''' + ISNULL(CONVERT(VARCHAR(100), @FloatVariable), '') + ''') '

PRINT(@DynamicSQL)

EXEC(@DynamicSQL)
Run Code Online (Sandbox Code Playgroud)

打印:

SELECT
    DateVariableContents = CONVERT(DATETIME, 'Mar 21 2019  3:27PM'),
    StringVariableContents = '',
    FloatVariableContents = CONVERT(FLOAT, '15.124') 
Run Code Online (Sandbox Code Playgroud)

结果:

DateVariableContents        StringVariableContents  FloatVariableContents
2019-03-21 15:28:00.000                             15.124
Run Code Online (Sandbox Code Playgroud)