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

Running statements in cursor returns Invalid object name error (SQL Server 2014)

我正在尝试执行从游标获得的语句,但我一直收到 "Invalid object name" 错误。首先,游标从 table 中提取信息,其中一列是数据库名称,另一列是 SQL 语句。它是这样定义的:

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

然后,我定义两个命令:

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

所以 cmd1 实际上只是 "USE DBName",其中 DBName 是数据库的名称,而 cmd2 是 SQL 在该数据库上 运行 的语句。

出于某种原因,每当我随后遍历游标时:

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

我收到一条错误消息:

Msg 208, Level 16, State 6, Procedure NameOfView, Line 34
Invalid object name 'dbo.NameOfView'.

我试过向 cmd1 添加一个 "GO" 命令,但它没有用(我猜 GO 只适用于客户端工具)。我尝试使用 "exec(@cmd1)" 而不是 exec sp_executesql(@cm1)”。如果我试图将其设为一个命令而不是两个,它会显示 "ALTER VIEW must be the first statement in a query batch."

我该怎么做才能使光标正常工作?

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

光标代码

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)

遍历游标

open commands
fetch next from commands into @cmd1, @cmd2
while @@FETCH_STATUS=0
begin
declare @cmd3 VARCHAR(MAX) = CONCAT(@cmd1, '; declare @cmd1 varchar(max) = ''', @cmd2, ''' exec(@cmd1)')
exec(@cmd3)
fetch next from commands into @cmd1, @cmd2
end
close commands
deallocate commands

你的问题是上下文切换。

打印出结果将为您提供一个可以正确更改数据库并更改架构的工作脚本。但那是因为它会在您的查询 window.

的上下文中全部 运行

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

如果我运行下面的脚本,输出是"master"。在 @cmd1 中,我成功切换到 MSDB,但是一旦该命令完成,上下文就会丢失,我又回到了 MASTER。 @Cmd2 然后 运行s 在它自己的上下文中,它没有从调用它的数据库中切换,所以它在 MASTER

中 运行s
 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)