执行动态查询并将值分配给两个变量

Posted

技术标签:

【中文标题】执行动态查询并将值分配给两个变量【英文标题】:Execute dynamic query and assign values into two variables 【发布时间】:2018-09-10 12:09:45 【问题描述】:

我有以下动态查询要执行并将结果分配给两个变量。

DECLARE @MinDate VARCHAR(10) = ''
DECLARE @MaxDate VARCHAR(10) = ''

SET @SQL = 'SELECT @MinDate = Convert(Varchar,Cast(Min(ColumnDate) AS DATE),105),
                   @MaxDate = Convert(Varchar,Cast(Max(ColumnDate) AS DATE),105)
            FROM ['+@Table+']';

PRINT(@SQL);
EXEC(@SQL)

PRINT(@MinDate);
PRINT(@MaxDate);

但我收到一个错误:

Msg 137, Level 15, State 1, Line 5 必须声明标量变量 “@MaxDate”。

【问题讨论】:

EXEC 无法分配不在其自己的本地范围内的变量。使用sp_executesql 和输出参数(例如DECLARE @d DATETIME; EXEC sp_executesql N'SELECT @d = GETDATE()', N'@d DATETIME OUTPUT', @d = @d OUTPUT; SELECT @d;)。 您所拥有的非常对注入开放。至少考虑使用QUOTENAME 【参考方案1】:

正如@Jeroen Mostert 在 cmets 中正确所说,您需要使用 sp_executesql 而不是 EXEC

sp_executesql允许为动态SQL提供参数,这些参数可以标记为OUTPUT,这里需要。

此外,最好使用适当的参数来防止 SQL 注入问题。在您的示例中,@MinDate@MaxDate 可以并且应该作为正确的参数。 @Table 不能成为参数,因此它将保持连接到 SQL 字符串。只有这部分对 SQL 注入开放。

这是一个例子:

DECLARE @MinDate_ VARCHAR(10) = '';
DECLARE @MaxDate_ VARCHAR(10) = '';
DECLARE @SQL nvarchar(max);

SET @SQL = 
    'SELECT 
        @MinDate = Convert(Varchar,Cast(Min(ColumnDate) AS DATE),105),
        @MaxDate = Convert(Varchar,Cast(Max(ColumnDate) AS DATE),105)
    FROM ['+@Table+']';

EXEC sp_executesql @SQL
    ,N'@MinDate VARCHAR(10) OUTPUT, @MaxDate VARCHAR(10) OUTPUT'
    ,@MinDate = @MinDate_ OUTPUT
    ,@MaxDate = @MaxDate_ OUTPUT
;

SELECT @MinDate_, @MaxDate_;

注意,您必须指定OUTPUT 两次。

对于在动态 SQL 外部和动态 SQL 内部声明的参数,您可以使用相同的名称 @MinDate,但我更喜欢给它们起不同的名称(@MinDate@MinDate_),所以我不会混淆什么是什么。

【讨论】:

【参考方案2】:

您可以尝试将变量放在字符串中:

SET @SQL = '
DECLARE @MinDate VARCHAR(10) = ''''
DECLARE @MaxDate VARCHAR(10) = ''''

SELECT @MinDate = Convert(Varchar,Cast(Min(ColumnDate) AS DATE),105),
       @MaxDate = Convert(Varchar,Cast(Max(ColumnDate) AS DATE),105)
FROM ['+@Table+']

PRINT(@MinDate)
PRINT(@MaxDate)
            '
EXEC(@SQL)

【讨论】:

这仍然很容易被注入。

以上是关于执行动态查询并将值分配给两个变量的主要内容,如果未能解决你的问题,请参考以下文章

My SQL 动态查询执行并将输出输出到存储过程中的变量中

如何用SQL代码将动态查询结果赋值给变量?

oracle动态查询通过sql获取游标变量

SQL查询动态列的方法

如何将相同的事件侦听器分配给 Vue.js 中动态创建的按钮并将对象的值作为参数传递给它?

R:将值分配给数据框中的动态变量时遇到问题