在游标中运行语句返回无效的对象名称错误(SQL Server 2014)

时间:2018-09-20 17:32:06

标签: sql-server sql-server-2014

我试图执行从游标获得的语句,并且不断收到“无效的对象名称”错误。首先,游标从一个表中提取信息,该表的一列具有数据库名称,而另一列具有SQL语句。定义如下:

ng-template

然后,我定义两个命令:

DECLARE commands CURSOR FOR 
    SELECT 
        REPLACE(DBNAME, DBNAME, 'USE ' + DBNAME),
        REPLACE(REPLACE(REPLACE(DESCRIPTION, 'OLDLINKEDSERVER', 'NEWLINKEDSERVER'), 'CREATE VIEW', 'ALTER VIEW'), 'CREATE  VIEW', 'ALTER VIEW') AS CMD
    FROM 
        #TMP2

因此,cmd1实际上只是“ USE DBName”,其中DBName是数据库的名称,而cmd2是要在该数据库上运行的SQL语句。

由于某种原因,每当我遍历游标时:

DECLARE @cmd1 NVARCHAR(MAX)
DECLARE @cmd2 NVARCHAR(MAX)

我看到一条错误消息:

  

消息208,级别16,状态6,过程NameOfView,第34行
  无效的对象名称'dbo.NameOfView'。

我尝试向cmd1添加一个“ GO”命令,但没有成功(我想GO仅对客户端工具有用)。我尝试使用“ exec(@ cmd1)”代替exec sp_executesql(@ cm1)“。如果我尝试使它成为一个命令而不是两个命令,则它说“ ALTER VIEW必须是查询批处理中的第一个语句。” < / p>

如何使光标正常工作?

编辑:感谢IsItGreyOrGray,以下代码是我找到的有效解决方案(不确定是否应该将其编辑到原始帖子中,或创建一个新帖子):

光标代码

OPEN Commands

FETCH NEXT FROM Commands INTO @cmd1, @cmd2

WHILE @@FETCH_STATUS = 0
BEGIN
    EXEC sp_executesql @cmd1
    EXEC sp_executesql @cmd2

    FETCH NEXT FROM Commands INTO @cmd1, @cmd2
END

CLOSE commands
DEALLOCATE commands

声明

declare commands cursor for
SELECT REPLACE(DBNAME,DBNAME, 'USE ' + DBNAME),
REPLACE(REPLACE(REPLACE(DESCRIPTION,'OLDLINKEDSERVER', 'NEWLINKEDSERVER'),'CREATE VIEW', 'ALTER VIEW'), '''', '''''') AS CMD
FROM #TMP2

通过光标迭代

declare @cmd1 varchar(max)
declare @cmd2 varchar(max)

1 个答案:

答案 0 :(得分:1)

您的问题是上下文切换。

打印出结果将为您提供一个有效的脚本,该脚本可正确更改数据库并进行模式更改。但这是因为它们都将在查询窗口的上下文中运行。

但是,每个EXEC都在各自的上下文中运行。

如果我运行以下脚本,则输出为“ master”。在@ cmd1中,我成功切换到MSDB,但是一旦该命令完成,上下文就会丢失,并且我将返回MASTER。然后,@ Cmd2在其自己的上下文中运行,该上下文尚未从调用它的数据库中切换,因此它在MASTER中运行

 USE master
 GO
 DECLARE @cmd1 VARCHAR(1000) = 'USE msdb'
 DECLARE @cmd2 VARCHAR(1000) = 'SELECT DB_NAME()'

 EXEC(@cmd1)
 EXEC(@cmd2)

为了使光标执行有效,您需要将@ cmd1与@ cmd2组合在一起,以使单个可执行变量与

相似。
'USE [database1]; CREATE TABLE test (id INT)'

由于遇到查询批处理失败,您可能需要嵌套执行...

此操作失败:

USE master
GO

DECLARE @cmd1 VARCHAR(1000) = 'USE msdb'
DECLARE @cmd2 VARCHAR(1000) = 'create procedure test as SELECT DB_NAME()'
DECLARE @cmd3 VARCHAR(MAX) = CONCAT(@cmd1, ' ', @cmd2)
EXEC (@cmd3)

成功:

DECLARE @cmd1 VARCHAR(1000) = 'USE msdb'
DECLARE @cmd2 VARCHAR(1000) = 'create procedure test as SELECT DB_NAME()'
DECLARE @cmd3 VARCHAR(MAX) = CONCAT(@cmd1, '; declare @cmd1 varchar(max) = ''', @cmd2,''' exec(@cmd1)' )
EXEC (@cmd3)