如何使用变量动态地在SELECT查询中包含列?

时间:2014-05-01 20:44:26

标签: sql-server

使用MS Sql Server

我正在执行以下代码:

SELECT @Fieldname = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @TableName
   AND ORDINAL_POSITION = @FIELD

它将 IsPrimary 分配给@Fieldname,这是预期的答案。但是当我执行这一行时:

SET @MyField =  (SELECT @Fieldname FROM inserted WHERE FileID = @FileID)

@MyField也被赋值 IsPrimary ,而不是1,IsPrimary字段中包含的值。

(注意:执行SELECT IsPrimary FROM插入WHERE FileID = @FileID正常工作并返回预期值1)

什么是正确的sql语句?

2 个答案:

答案 0 :(得分:1)

它不会那样工作。您不能使用变量来表示查询的部分内容。

但是,您可以将查询字符串动态构建到VARCHAR变量中,并使用EXEC函数执行它。它伴随着各种权衡(不同的安全上下文,sql注入攻击的风险等等),但它会按照你期望的方式工作。

答案 1 :(得分:0)

详细说明Crono的答案,并修复我之前的答案,“正确的(T-)SQL语句”将是这样的:

SELECT FileID = CAST(1 AS int), CreatedAt = GETDATE()
INTO #inserted;

DECLARE @Fieldname  varchar(30),
        @MyField    datetime,
        @FileID     int,
        @sql        nvarchar(4000);

SELECT  @Fieldname = 'CreatedAt',
        @FileID = 1;

SELECT @sql = 'SELECT @MyField = ' + @Fieldname + ' FROM #inserted WHERE FileID = ' + CAST(@FileID AS varchar) + ';';

EXEC sp_executesql @sql, N'@MyField datetime OUTPUT', @MyField OUTPUT;

SELECT [@MyField] = @MyField;

DROP TABLE #inserted;

我添加了代码来创建临时表#inserted,这样您就可以按原样运行示例代码。

我很高兴我在下面提到了Erland的文章,因为它提出了一些关于动态SQL的重要内容,这解释了为什么我以前的答案不起作用:

  

在动态SQL块中,您无法访问本地变量(包括表变量)或调用存储过程的参数。但是,如果使用sp_executesql,则可以将参数(in和out)传递给动态SQL块。

请参阅Erland Sommarskog的(经典)The Curse and Blessings of Dynamic SQL,了解有关使用动态SQL(即生成SQL然后执行它)的更多信息的加载