La colonne de test existe, Ajouter une colonne et Mettre à jour la colonne

J'essaie d'écrire un script de mise à jour de database SQL Server. Je veux tester l'existence d'une colonne dans une table, puis si elle n'existe pas append la colonne avec une valeur par défaut, et enfin mettre à jour cette colonne en fonction de la valeur actuelle d'une colonne différente dans la même table. Je veux que ce script soit exécutable plusieurs fois, la première fois en mettant à jour la table et lors des exécutions suivantes, le script devrait être ignoré. Mon script ressemble actuellement à ceci:

IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'PurchaseOrder' AND COLUMN_NAME = 'IsDownloadable') BEGIN ALTER TABLE [dbo].[PurchaseOrder] ADD [IsDownloadable] bit NOT NULL DEFAULT 0 UPDATE [dbo].[PurchaseOrder] SET [IsDownloadable] = 1 WHERE [Ref] IS NOT NULL END 

SQL Server renvoie une erreur "Nom de colonne invalide" IsDownloadable "", c'est-à-dire que je dois valider le DDL avant de pouvoir mettre à jour la colonne. J'ai essayé différentes permutations mais je n'arrive nulle part rapidement.

    Ce script ne sera pas exécuté correctement à less que la colonne existe déjà, ce qui est exactement lorsque vous n'en avez pas besoin.

    Les scripts SQL doivent être analysés avant de pouvoir être exécutés. Si la colonne n'existe pas au moment de l'parsing du script, l'parsing échoue. Peu importe que vos scripts créent la colonne plus tard; l'parsingur n'a aucun moyen de le savoir.

    Vous devez mettre une instruction GO (séparateur de lots) si vous voulez accéder à une colonne que vous venez d'append. Cependant, une fois que vous faites cela, vous ne pouvez plus maintenir aucun stream de contrôle ou variables du lot précédent – c'est comme exécuter deux scripts séparés. Cela rend difficile de faire à la fois DDL et DML, conditionnellement, en même time.

    La solution de contournement la plus simple, que je reorderais probablement pour vous parce que votre DML n'est pas très complexe, consiste à utiliser le SQL dynamic, que l'parsingur n'essaiera pas d'parsingr jusqu'à ce que "runtime":

     IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'PurchaseOrder' AND COLUMN_NAME = 'IsDownloadable') BEGIN ALTER TABLE [dbo].[PurchaseOrder] ADD [IsDownloadable] bit NOT NULL DEFAULT 0 EXEC sp_executesql N'UPDATE [dbo].[PurchaseOrder] SET [IsDownloadable] = 1 WHERE [Ref] IS NOT NULL' END 

    Essayez d'append une instruction "GO" après la table ALTER.

    C'était une nouvelle pour moi, mais il est dit ici que toutes les instructions d'un lot (celles qui précèdent le GO) sont compilées dans un plan de requête.) Sans GO dans le SQL, le plan entier est effectivement une requête.

    EDIT: Puisque GO donne une erreur de syntaxe (ce qui m'a paru étrange), j'ai créé quelque chose de similaire, et j'ai trouvé que ça fonctionnait

     declare @doUpdate bit; SELECT @doUpdate = 0; IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'PurchaseOrder' AND COLUMN_NAME = 'IsDownloadable') BEGIN SELECT @doUpdate=1 END IF @doUpdate<>0 ALTER TABLE [dbo].[PurchaseOrder] ADD [IsDownloadable] bit NOT NULL DEFAULT 0 IF @doUpdate<>0 UPDATE [dbo].[PurchaseOrder] SET [IsDownloadable] = 1 WHERE [Ref]=0 COMMIT TRAN