TSQL - Как использовать GO внутри блока BEGIN.. END?
Я генерирую script для автоматической миграции изменений из нескольких баз данных разработки в процесс постановки/производства. В принципе, он берет кучу скриптов изменений и объединяет их в один script, обертывая каждый script в инструкции IF whatever BEGIN ... END
.
Однако для некоторых сценариев требуется оператор GO
, так что, например, анализатор SQL знает о новом столбце после его создания.
ALTER TABLE dbo.EMPLOYEE
ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
GO -- Necessary, or next line will generate "Unknown column: EMP_IS_ADMIN"
UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever
Однако, как только я завершу это в блок IF
:
IF whatever
BEGIN
ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
GO
UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever
END
Не удается, потому что я отправляю BEGIN
без соответствия END
. Однако, если я удаляю GO
, он снова жалуется на неизвестный столбец.
Есть ли способ создать и обновить один и тот же столбец в одном блоке IF
?
Ответы
Ответ 1
Я в конечном итоге заставил его работать, заменив каждый экземпляр GO
на собственную строку
END
GO
---Automatic replacement of GO keyword, need to recheck IF conditional:
IF whatever
BEGIN
Это гораздо предпочтительнее, чем перенос каждой группы операторов в строку, но по-прежнему далек от идеала. Если кто-то найдет лучшее решение, опубликуйте его, и я приму его.
Ответ 2
GO
не является SQL - это просто разделитель пакетов, используемый в некоторых инструментах MS SQL.
Если вы этого не используете, вам нужно убедиться, что инструкции выполняются отдельно - либо в разных партиях, либо с использованием динамического SQL для населения (спасибо @gbn):
IF whatever
BEGIN
ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL;
EXEC ('UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever')
END
Ответ 3
У меня была такая же проблема, и в конце концов мне удалось ее решить с помощью SET NOEXEC.
IF not whatever
BEGIN
SET NOEXEC ON;
END
ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
GO
UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever
SET NOEXEC OFF;
Ответ 4
Вы можете попробовать sp_executesql
, разделив содержимое между каждым оператором GO
на отдельную строку, которая будет выполнена, как показано в пример ниже. Кроме того, существует переменная @statementNo для отслеживания того, какой оператор выполняется для легкой отладки, где произошло исключение. Номера строк будут относиться к началу соответствующего номера оператора, вызвавшего ошибку.
BEGIN TRAN
DECLARE @statementNo INT
BEGIN TRY
IF 1=1
BEGIN
SET @statementNo = 1
EXEC sp_executesql
N' ALTER TABLE dbo.EMPLOYEE
ADD COLUMN EMP_IS_ADMIN BIT NOT NULL'
SET @statementNo = 2
EXEC sp_executesql
N' UPDATE dbo.EMPLOYEE
SET EMP_IS_ADMIN = 1'
SET @statementNo = 3
EXEC sp_executesql
N' UPDATE dbo.EMPLOYEE
SET EMP_IS_ADMIN = 1x'
END
END TRY
BEGIN CATCH
PRINT 'Error occurred on line ' + cast(ERROR_LINE() as varchar(10))
+ ' of ' + 'statement # ' + cast(@statementNo as varchar(10))
+ ': ' + ERROR_MESSAGE()
-- error occurred, so rollback the transaction
ROLLBACK
END CATCH
-- if we were successful, we should still have a transaction, so commit it
IF @@TRANCOUNT > 0
COMMIT
Вы также можете легко выполнять многострочные операторы, как показано в приведенном выше примере, просто обернув их в одинарные кавычки ('
). Не забудьте избежать каких-либо одиночных кавычек, содержащихся внутри строки, с двойной одинарной кавычкой (''
) при создании сценариев.
Ответ 5
Вы можете заключать инструкции в BEGIN и END вместо GO inbetween
IF COL_LENGTH('Employees','EMP_IS_ADMIN') IS NULL --Column does not exist
BEGIN
BEGIN
ALTER TABLE dbo.Employees ADD EMP_IS_ADMIN BIT
END
BEGIN
UPDATE EMPLOYEES SET EMP_IS_ADMIN = 0
END
END
(проверено в базе данных Northwind)
Изменить: (возможно, проверено на SQL2012)
Ответ 6
Я использовал RAISERROR
в прошлом для этого
IF NOT whatever BEGIN
RAISERROR('YOU''RE ALL SET, and sorry for the error!', 20, -1) WITH LOG
END
ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
GO
UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever
Ответ 7
Вы можете попробовать это решение:
if exists(
SELECT...
)
BEGIN
PRINT 'NOT RUN'
RETURN
END
--if upper code not true
ALTER...
GO
UPDATE...
GO
Ответ 8
Вы можете включить операторы GOTO
и LABEL
, чтобы пропустить код, тем самым оставив ключевые слова GO
неповрежденными.