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 неповрежденными.