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
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.
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)
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