SQL Server 变量列名?

24
我想知道为什么我不能像这样使用变量作为列名:
declare @a as varchar;
set @a='TEST'

select @a from x;

谢谢

5个回答

23

你不能这样做是因为在SQL编译时并不知道 @a 的值(假设在实际情况中,@a 是某个参数而不是像你示例中那样硬编码的)。

相反,你可以这样做:

declare @a as varchar; 
set @a='TEST' 

declare @sql nvarchar(max)
set @sql = 'select [' + replace(@a, '''', '''''') + '] from x'

exec sp_executesql @sql

但要小心,这是一个安全漏洞(SQL注入攻击),如果你不能信任或无法清理@a,则不应该这样做。


4
除非您先阅读了这篇文章,否则请勿使用动态SQL: http://www.sommarskog.se/dynamic_sql.html - HLGEM

5

因为不允许这样做。

你可以使用动态SQL查询代替:

declare @a as varchar;
set @a='TEST'
exec ('select ' + @a + ' from x')

4
问题是为什么不允许,而不是如何绕过它。回答“因为不允许”并没有太大的帮助。我认为应该将其翻译为:“这个问题问的是为什么不允许,而不是如何绕过它。回答‘因为不允许’并没有太大的帮助。” - David M
@David M:是的,这只是一个解决方法。你的回答很有帮助。 - Oleks
1
感谢 exec - 它比 exec sp_executesql 更容易记忆。我总是记得使用这个存储过程时会出现错误,例如“不允许执行此过程”。 - Tomasz Gandor

4

由于列名在SQL语句的编译时而非运行时被解析,因此需要注意。


3

如果可选择的列不太多,可以考虑使用CASE WHEN语句?

DECLARE @ColName VARCHAR(50) = 'Test1'

SELECT [Foo], [Bar],
CASE 
  WHEN @ColName = 'Test1' THEN [Test1]
  WHEN @ColName = 'Test2' THEN [Test2]
  WHEN @ColName = 'Test3' THEN [Test3]
  WHEN @ColName = 'Test4' THEN [Test4]
  ELSE [TestDefault]
END [TestResult]
FROM [TableName];

这样可以避免使用任何 EXEC 命令。


3

使用sp_executesql来实现此功能。

Example
SET @SQLString = N'SELECT *
    FROM table1
    WHERE timet = @time and items in (@item)';


DECLARE @SQLString nvarchar(500);
DECLARE @ParmDefinition nvarchar(500);

SET @ParmDefinition = N'@time timestamp,
    @item varchar(max) ';

EXECUTE sp_executesql
    @SQLString
    ,@ParmDefinition
    ,@time = '2010-04-26 17:15:05.667'
    ,@item = '''Item1'',''Item2'',''Item3'',''Item4'''
    ;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接