web-dev-qa-db-fra.com

TSQL - Comment utiliser GO à l'intérieur d'un bloc BEGIN .. END?

Je génère un script pour migrer automatiquement les modifications de plusieurs bases de données de développement vers la mise en scène/production. Fondamentalement, il prend un tas de changements de scripts, et les fusionne en un seul script, enveloppant chaque script dans un IF whatever BEGIN ... END déclaration.

Cependant, certains scripts nécessitent une instruction GO pour que, par exemple, l'analyseur SQL connaisse une nouvelle colonne après sa création.

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

Cependant, une fois que j'ai enveloppé cela dans un bloc 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

Il échoue car j'envoie un BEGIN sans END correspondant. Cependant, si je supprime le GO, il se plaint à nouveau d'une colonne inconnue.

Existe-t-il un moyen de créer et de mettre à jour la même colonne dans un seul bloc IF?

Je l'ai finalement fait fonctionner en remplaçant chaque instance de GO sur sa propre ligne par

END
GO

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

Ceci est grandement préférable à l'encapsulation de chaque groupe d'instructions dans une chaîne, mais est toujours loin idéal. Si quelqu'un trouve une meilleure solution, postez-la et je l'accepterai à la place.

GO n'est pas SQL - c'est simplement un séparateur de lots utilisé dans certains outils MS SQL.

Si vous ne l'utilisez pas, vous devez vous assurer que les instructions sont exécutées séparément - soit dans des lots différents, soit en utilisant du SQL dynamique pour la population (merci @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
40
Oded

Tu pourrais essayer sp_executesql , divisant le contenu entre chaque instruction GO en une chaîne distincte à exécuter, comme illustré dans l'exemple ci-dessous. En outre, il existe une variable @statementNo pour suivre quelle instruction est exécutée pour un débogage facile où une exception s'est produite. Les numéros de ligne seront relatifs au début du numéro de relevé pertinent à l'origine de l'erreur.

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

Vous pouvez également exécuter facilement des instructions sur plusieurs lignes, comme illustré dans l'exemple ci-dessus, en les enveloppant simplement entre guillemets simples ('). N'oubliez pas d'échapper les guillemets simples contenus dans la chaîne avec un double guillemet simple ('') lors de la génération des scripts.

16
mellamokb

Vous pouvez placer les instructions entre BEGIN et END au lieu de GO entre les deux.

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

(Testé sur la base de données Northwind)

Edit: (Probablement testé sur SQL2012)

7
Andy Joiner

J'ai utilisé RAISERROR dans le passé pour cela

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
kavun