Выполнение операторов в курсоре возвращает ошибку «Недопустимое имя объекта» (SQL Server 2014) - PullRequest
0 голосов
/ 20 сентября 2018

Я пытаюсь выполнить операторы, полученные от курсора, и получаю сообщение об ошибке «Неверное имя объекта».Начнем с того, что курсор извлекает информацию из таблицы, в которой имя базы данных находится в одном столбце, а оператор 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

Я получаю сообщение об ошибке:

Сообщение 208, Уровень 16, Состояние 6, Имя процедурыOfView, Строка 34
Неверное имя объекта 'dbo.NameOfView'.

Я пытался добавить команду "GO"до cmd1, но это не сработало (думаю, GO подходит только для клиентских инструментов).Я попытался использовать "exec (@ cmd1)" вместо exec sp_executesql (@ cm1) ". Если я попытался сделать из него одну команду вместо двух, то он говорит:" ALTER VIEW должен быть первым оператором в пакете запроса. "

Что я могу сделать, чтобы заставить мой курсор работать правильно?

РЕДАКТИРОВАТЬ: Следующий код является рабочим решением, которое я нашел, благодаря IsItGreyOrGray (не уверен, если я долженотредактируйте его в моем исходном сообщении или создайте новый):

код для курсора

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

1 Ответ

0 голосов
/ 20 сентября 2018

Ваша проблема - переключение контекста.

Распечатка результатов даст вам рабочий скрипт, который корректно изменяет базы данных и вносит изменения в схему.Но это потому, что все это будет выполняться в контексте вашего окна запроса.

Однако каждый EXEC выполняется в своем собственном контексте.

Если я запускаю следующий скрипт, вывод будет "master".В @ cmd1 я успешно переключаюсь на MSDB, но как только эта команда завершена, контекст теряется, и я снова в МАСТЕРЕ.Затем @ 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)
...