Logique conditionnelle en post-déploiement.script sql utilisant SQLCMD

J'utilise un projet de base de données SQL 2008 (dans visual studio) pour gérer le schéma et les données de test initiales de mon projet. Le projet atabase utilise un post-déploiement qui inclut un certain nombre d'Autres scripts utilisant la syntaxe ":r " de SQLCMD.

Je voudrais pouvoir inclure conditionnellement certains fichiers basés sur une variable SQLCMD. Cela me permettra d'exécuter le projet plusieurs fois avec notre build nocturne pour configurer diverses versions de la base de données avec différentes configurations des données (pour un multi-locataire système).

J'ai essayé ce qui suit:

IF ('$(ConfigSetting)' = 'Configuration1')
  BEGIN
    print 'inserting specific configuration' 
:r .Configuration1Data.sql
  END
ELSE
  BEGIN
    print 'inserting generic data' 
:r .GenericConfigurationData.sql
  END

Mais je reçois une erreur de compilation: SQL01260: une erreur d'analyseur fatale s'est produite: Script.Post-déploiement.sql

Quelqu'un A vu cette erreur ou réussi à configurer leur script de post-déploiement des flexibles de cette façon? Ou est-ce que je vais à ce sujet dans le mauvais sens complètement?

Merci, Rob

P.S. j'ai aussi essayé de changer cela pour que le chemin d'accès au fichier soit une variable, similaire à ce post . Mais cela me donne une erreur en disant que le chemin est incorrect.

47
demandé sur Community 2011-08-22 21:15:55

6 réponses

Mise à JOUR

J'ai maintenant découvert que la syntaxe if/else ci-dessus ne fonctionne pas pour moi car certains de mes scripts liés nécessitent une instruction GO. Essentiellement, le :r importe simplement les scripts en ligne, donc cela devient sytax invalide.

Si vous avez besoin d'une instruction GO dans les scripts liés (comme je le fais), il n'y a pas de moyen facile de contourner cela, j'ai fini par créer plusieurs scripts de déploiement post, puis changer mon projet pour écraser le script de déploiement post principal lors de la construction temps en fonction de la configuration de construction. Cela fait maintenant ce dont j'ai besoin, mais il semble qu'il devrait y avoir un moyen plus facile!

Pour tous ceux qui ont besoin de la même chose - j'ai trouvé ce post utile

Donc, dans mon projet, j'ai les fichiers post-déploiement suivants:

  • Script.Post-déploiement.sql (fichier vide qui sera remplacé)
  • par défaut.Script.Post-déploiement.sql (liens vers des scripts nécessaires pour les données standard config)
  • Configuration1.Script.Post-déploiement.sql (liens vers des scripts nécessaires pour une configuration de données spécifique)

J'ai ensuite ajouté ce qui suit à la fin du fichier de projet (clic droit pour décharger, puis clic droit modifier):

  <Target Name="BeforeBuild">
      <Message Text="Copy files task running for configuration: $(Configuration)" Importance="high" />
      <Copy Condition=" '$(Configuration)' == 'Release' " SourceFiles="Scripts\Post-Deployment\Default.Script.PostDeployment.sql" DestinationFiles="Scripts\Post-Deployment\Script.PostDeployment.sql" OverwriteReadOnlyFiles="true" />
      <Copy Condition=" '$(Configuration)' == 'Debug' " SourceFiles="Scripts\Post-Deployment\Default.Script.PostDeployment.sql" DestinationFiles="Scripts\Post-Deployment\Script.PostDeployment.sql" OverwriteReadOnlyFiles="true" />
      <Copy Condition=" '$(Configuration)' == 'Configuration1' " SourceFiles="Scripts\Post-Deployment\Configuration1.Script.PostDeployment.sql" DestinationFiles="Scripts\Post-Deployment\Script.PostDeployment.sql" OverwriteReadOnlyFiles="true" />
  </Target>

Enfin, vous devrez configurer les configurations de construction correspondantes dans la solution.

Aussi, pour tous ceux qui essaient d'autres solutions de contournement, j'ai aussi essayé ce qui suit sans aucune chance:

  1. Création d'un événement post build à copier les fichiers au lieu d'avoir à pirater le fichier de projet XML. Je n'ai pas pu faire fonctionner cela parce que je ne pouvais pas former le chemin correct vers le fichier de script post-déploiement. Cette question de connexion décrit le problème

  2. Utilisation de variables pour que le chemin du script passe à la commande: r. Mais je suis tombé sur plusieurs erreurs avec cette approche.

32
répondu Rob Bird 2011-08-25 10:43:57

Voici comment je gère le déploiement conditionnel dans le processus de post-déploiement pour déployer les données de test pour le débogage mais pas la configuration de publication.

Tout d'abord, dans l'Explorateur de solutions, ouvrez le dossier Propriétés du projet et cliquez avec le bouton droit pour ajouter un nouveau SqlCmd.fichier de variables.

Nommez le fichier Debug.sqlcmdvars.

Dans le fichier, ajoutez vos variables personnalisées, puis ajoutez une variable finale appelée $(BuildConfiguration), et définissez la valeur sur Debug.

Répétez le processus pour créer un Publier.sqlcmdvars, définir le $(BuildConfiguration) à libérer.

Maintenant, configurez vos configurations: Ouvrez la page Propriétés du projet dans L'onglet déployer. Dans la liste déroulante supérieure, définissez la configuration à déboguer. Dans la liste déroulante du bas, (variables de commande Sql), définissez le fichier sur Properties \ Debug.sqlcmdvars.

Répéter pour la Libération comme: Dans la liste déroulante supérieure, définissez la configuration à libérer. Dans la liste déroulante du bas, (variables de commande Sql), définissez le fichier sur Propriétés\Release.sqlcmdvars.

Maintenant, dans votre Script.Post-déploiement.fichier sql, vous pouvez spécifier une logique conditionnelle telle que:

IF 'Debug' = '$(BuildConfiguration)'
BEGIN
PRINT '***** Creating Test Data for Debug configuration *****';
:r .\TestData\TestData.sql
END

Dans l'Explorateur de solutions, faites un clic droit sur la solution de niveau supérieur et ouvrez Configuration Manager. Vous pouvez spécifier quelle configuration est active pour votre build. Vous pouvez également spécifier la configuration sur MSBUILD.Ligne de commande EXE.

Voilà - maintenant vos builds de développeur ont des données de test, mais pas votre version de version!

13
répondu Rob McCauley 2012-01-13 21:14:08

J'ai réussi à contourner le problème en utilisant le noexec méthode.

Donc, au lieu de ceci:

IF ('$(ConfigSetting)' = 'Configuration1')
 BEGIN
    print 'inserting specific configuration' 
    :r .\Configuration1\Data.sql
 END

J'ai inversé Le conditionnel et défini NOEXEC sur pour ignorer les instructions importées ainsi:

IF ('$(ConfigSetting)' <> 'Configuration1')
    SET NOEXEC ON

:r .\Configuration1\Data.sql

SET NOEXEC OFF

Assurez-vous de le désactiver si vous souhaitez exécuter des instructions ultérieures.

13
répondu Simon Calvin 2017-05-23 12:26:25

Comme Rob a travaillé, les instructions GO ne sont pas autorisées dans les scripts SQL liés car cela les imbriquerait dans les instructions BEGIN/END.

Cependant, j'ai une solution différente - si possible, supprimez toutes les instructions GO des scripts référencés, et mettez-en une seule après L'instruction END:

IF '$(DeployTestData)' = 'True'
BEGIN
    :r .\TestData\Data.sql
END
GO -- moved from Data.sql

Notez que j'ai également créé une nouvelle variable dans mon fichier sqlcmdvars appelé $(DeployTestData) qui me permet d'activer/désactiver le déploiement du script de test.

8
répondu Dunc 2012-08-29 14:44:33

J'ai trouvé un hack d'un blog MSDN {[8] } qui a assez bien fonctionné. L'astuce consiste à écrire les commandes dans un fichier de script temporaire, puis à exécuter ce script à la place. Fondamentalement l'équivalent de SQL dynamique pour SQLCMD.

-- Helper newline variable
:setvar CRLF "CHAR(13) + CHAR(10)"
GO
-- Redirect output to the TempScript.sql file
:OUT $(TEMP)\TempScript.sql

IF ('$(ConfigSetting)' = 'Configuration1')
  BEGIN
    PRINT 'print ''inserting specific configuration'';' + $(CRLF)   
    PRINT ':r .\Configuration1\Data.sql' + $(CRLF)
  END
ELSE
  BEGIN
    PRINT 'print ''inserting generic data'';' + $(CRLF) 
    PRINT ':r .\GenericConfiguration\Data.sql' + $(CRLF)
  END
GO
-- Change output to stdout
:OUT stdout

-- Now execute the generated script
:r $(TEMP)\TempScript.sql
GO

Le fichier TempScript.sql contiendra alors:

print 'inserting specific configuration';   
:r .\Configuration1\Data.sql

Ou

print 'inserting generic data';
:r .\GenericConfiguration\Data.sql

En Fonction de la valeur de $(ConfigSetting) et il n'y aura pas de problèmes avec GO déclarations etc. quand il est exécuté.

1
répondu kjbartel 2016-02-05 07:25:26

J'ai été inspiré par la solution de Rob Bird. Cependant, j'utilise simplement les événements de construction pour remplacer les scripts de déploiement post basés sur la configuration de construction sélectionnée.

  1. j'ai un script de post-déploiement "factice" vide.
  2. j'ai configuré un événement de pré-construction pour remplacer ce fichier "factice" en fonction de la configuration de construction sélectionnée (voir l'image ci-jointe).
  3. j'ai configuré un événement post-build pour replacer le fichier" factice " une fois la construction terminée (voir l'image ci-jointe). Le la raison en est que je ne veux pas générer de changements dans le contrôle des modifications après la construction.

Exemple de configuration des événements de construction

1
répondu Martin Karouš 2016-12-28 12:39:47