TSQL - Как использовать GO внутри блока BEGIN .. END? - PullRequest
85 голосов
/ 16 июня 2011

Я создаю сценарий для автоматической миграции изменений из нескольких баз данных разработки в стадию / производство. По сути, он берет несколько сценариев изменений и объединяет их в один сценарий, оборачивая каждый сценарий в оператор 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?

Ответы [ 7 ]

39 голосов
/ 16 июня 2011

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
32 голосов
/ 20 октября 2016

У меня была та же проблема, и в конце концов мне удалось ее решить, используя 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; 
16 голосов
/ 16 июня 2011

Вы можете попробовать 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

Вы также можете легко выполнить многострочные операторы, как показано в примере выше, просто заключив их водинарные кавычки (').Не забывайте избегать одиночных кавычек, содержащихся внутри строки, с двойной одинарной кавычкой ('') при создании сценариев.

8 голосов
/ 20 июня 2011

Я в конечном итоге заставил его работать, заменив каждый экземпляр GO в отдельной строке на

END
GO

---Automatic replacement of GO keyword, need to recheck IF conditional:
IF whatever
BEGIN

Это гораздо предпочтительнее, чем оборачивать каждую группу операторов в строку, но все еще далеко от идеального. Если кто-нибудь найдет лучшее решение, опубликуйте его, и я приму его.

7 голосов
/ 16 октября 2013

Вы можете заключить операторы в BEGIN и END вместо GO между

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)

0 голосов
/ 09 мая 2019

Я использовал 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
0 голосов
/ 02 ноября 2012

Вы можете включить операторы GOTO и LABEL, чтобы пропустить код, оставив ключевые слова GO без изменений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...