SQL声明变量

16

能否有人帮我检查一下我的语句...

DECLARE @tblName varchar(MAX), 
        @strSQL varchar(MAX)

SET @tblName ='SELECT DISTINCT o.name as TableName 
                 FROM sysobjects o 
                 JOIN sysindexes x on o.id = x.id  
                WHERE o.name LIKE ''%empty%'''  

SET @strSQL = 'INSERT INTO @tblName VALUES(''trylng'', ''1'')'
EXEC (@strSQL)

我的错误是...

Msg 1087, Level 15, State 2, Line 1
必须声明表变量 "@tblName"。


3
希望返回的表格只有两列,并且数据类型匹配。 - OMG Ponies
@OMGPonies:当然是可插入的列。 - Andriy M
2个回答

12

你的@tblName属性存在于外部作用域,也就是“正常”代码行的作用域,但不存在于你在字符串中构建的SQL的内部作用域中....

你需要将代码修改为:

SET @strSQL = 'INSERT INTO ' + @tblName + ' VALUES(''trylng'', ''1'')'

然后它应该可以正常工作。

此外,您没有提到您的SQL Server版本 - 但是从SQL Server 2005或更新版本开始,您应该停止使用sysobjectssysindexes - 而是使用包含几乎相同信息但更易于获取的新sys模式。将您的查询更改为:

SET @tblName ='SELECT DISTINCT t.name as TableName 
               FROM sys.tables t
               INNER JOIN sys.indexes i on i.object_id = t.object_id  
               WHERE t.name LIKE ''%empty%'''  

请查看MSDN:查询SQL Server系统目录以获取有关新sys模式中可用内容及其最佳使用方法的更多信息!
如“rsbarro”所指出的:将此SQL语句放在引号中很奇怪 - 你也是使用EXEC(...)执行此语句吗?但是,你如何将值分配回@tblName属性?这并没有真正意义.....
如果要实际运行此查询来获取值,应该像这样:
 SELECT TOP 1 @tblName = t.name
 FROM sys.tables t
 INNER JOIN sys.indexes i on i.object_id = t.object_id  
 WHERE t.name LIKE '%empty%'

你需要在这里加入 TOP 1,以确保只获取一个值 - 否则如果选择多行,此语句可能会失败。


我有什么遗漏吗?为什么@tblName被单引号包裹?那不会将其设置为字符串而不是表名吗? - rsbarro
不,我的意思是第二个语句。它应该是SET @tblName = SELECT DISTINCT t.name...没有引号的吗?写成这样,@strSQL的值将为INSERT INTO SELECT DISTINCT t.Name as TableName...。我觉得那会是无效的,对吗? - rsbarro
@rsbarro:啊,好的-嗯,不确定-我假设OP也将使用EXEC(....)来执行该SQL语句。如果没有-那么你绝对是正确的,它不会起作用! - marc_s
1
很酷。我所在的地方已经很晚了,我以为我要么看到了一些新的语法,要么是我疯了... =] - rsbarro
另外一个问题是,既然与我们的“WHERE”匹配的表的列表在SYS.TABLES中,为什么我们需要使用join到SYS.INDEXES? - Argel Joseph
@ArgelJoseph:我不知道为什么你在使用 sys.indexes,那是你的声明,我只是试图让它工作。但你是对的 - 在那个声明中似乎不需要使用 sys.indexes ... - marc_s

6

我不确定你具体想要做什么,但我认为你想要像这样的东西:

DECLARE @tblName varchar(MAX), @strSQL varchar(MAX)
SET @tblName = 
    (select distinct o.name as TableName 
     from sysobjects o 
     join sysindexes x on o.id = x.id  
     where o.name LIKE '%empty%')
SET @strSQL = 'INSERT INTO [' + @tblName + '] VALUES(''trylng'', ''1'')'
exec (@strSQL)

话虽如此,在这里仍有一些需要注意的事项。您需要处理SELECT DISTINCT返回除单个记录之外的任何情况。此外,我不太理解在@strSQL中构建动态SQL的必要性,因为@tblName始终具有相同的值(因为WHERE子句中没有使用变量)。


1
+1,只有一个注意事项:通常在像这样的动态脚本中将名称合并到脚本中更安全,例如:'INSERT INTO ' + QUOTENAME(@tblName) + '…',而不是简单地在它们周围加上方括号。 - Andriy M

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