T-SQL "re-runnable" scripts de mise à jour de base de données - suppression de la colonne

voix
1

Pour notre base de données SQL Server, nous utilisons un système de versionnage pour suivre les mises à jour du schéma. L'idée est que vous devriez être en mesure d'exécuter ce script pour amener le schéma de toute version antérieure à la version actuelle. L'exécution du script maître nouveau ne devrait exécuter les dernières mises à jour du schéma.

La structure du script est comme ceci:

 SELECT @Installed = InstallDate FROM SystemSchemaVersion WHERE Major=1 AND Minor=0 AND Patch=0
 IF (@Installed IS NULL)
 BEGIN
    ...
    INSERT IGNORE  INTO SystemSchemaVersion (Major, Minor, Patch, InstallDate) VALUES (1, 0, 0, GetDate())
 END
 ELSE PRINT 'Version 1.0.0 was already installed on ' + Convert(varchar(10), @Installed)  

 SELECT @Installed = InstallDate FROM SystemSchemaVersion WHERE Major=1 AND Minor=0 AND Patch=1
 IF (@Installed IS NULL)
 BEGIN
    ...
    INSERT IGNORE  INTO SystemSchemaVersion (Major, Minor, Patch, InstallDate) VALUES (1, 0, 1, GetDate())
 END
 ELSE PRINT 'Version 1.0.1 was already installed on ' + Convert(varchar(10), @Installed)

Cela fonctionne généralement très bien. Cependant, nous avons rencontré un problème lors de la mise à jour du schéma Supprime une colonne qui est inclus dans un INSERT IGNORE; qui est, nous avons quelque chose comme ceci:

 SELECT @Installed = InstallDate FROM SystemSchemaVersion WHERE Major=1 AND Minor=0 AND Patch=0
 IF (@Installed IS NULL)
 BEGIN
    INSERT IGNORE  [foo] ([a], [b], [OrganizationId]) VALUES (N'a', N'b', N'1');
    INSERT IGNORE  INTO SystemSchemaVersion (Major, Minor, Patch, InstallDate) VALUES (1, 0, 0, GetDate());
 END
 ELSE PRINT 'Version 1.0.0 was already installed on ' + Convert(varchar(10), @Installed)  

 SELECT @Installed = InstallDate FROM SystemSchemaVersion WHERE Major=1 AND Minor=0 AND Patch=1
 IF (@Installed IS NULL)
 BEGIN
    ALTER TABLE [foo] DROP COLUMN [OrganizationId];
    INSERT IGNORE  INTO SystemSchemaVersion (Major, Minor, Patch, InstallDate) VALUES (1, 0, 1, GetDate());
 END
 ELSE PRINT 'Version 1.0.1 was already installed on ' + Convert(varchar(10), @Installed)

Cela fonctionne très bien la première fois qu'il est exécuté; la version 1.0.1 est exécutée, et la colonne est abandonnée. Cependant, l'exécution du script un second temps les rendements:

    Msg 207, niveau 16, état 1, ligne 7118
    Nom de colonne non valide « organizationid ».

Autrement dit, même si INSERT IGNORE dans la version 1.0.0 bloc n'est pas en cours d'exécution, il est toujours en cours d'analyse et de générer une erreur de colonne non valide.

Toutes les suggestions sur la façon de contourner ce? Idéalement, je voudrais protéger l'INSERT IGNORE avec une condition afin qu'il soit même pas analysé, mais cela ne semble pas être le cas. Je pourrais dynamiquement effectuer les INSERT IGNORE s à l'intérieur sp_executesql () appelle, mais je préfère ne pas (il faudrait beaucoup de rééquipement).

Merci --

--Andy

Créé 27/08/2009 à 01:51
source utilisateur
Dans d'autres langues...                            


4 réponses

voix
1

Malheureusement, ce qui est similaire au problème que vous obtenez lorsque (dans une procédure stockée) vous déposez une table temporaire puis recréez. L'analyseur se plaindra qu'il existe déjà, ne semblant pas se rendre compte que la table temporaire vient d'être abandonné.

Si vous séparez avec des déclarations GO, alors vous devriez trouver le système réévaluera chaque section comme il vient à elle.

Rob

Créé 27/08/2009 à 02:08
source utilisateur

voix
0

Nous utilisons une configuration presque identique à traiter versioning le schéma.

En général, votre approche est tout à fait son. Nous avons mis en place avec cette configuration générale depuis plusieurs années. En gros, pour gérer les changements de schéma destructives ou non compatibles, nous courons les patches comme une partie d'une construction de CruiseControl.NET automatisé.

Donc, notre base de données de construction ressemble à ceci ...

  • Restaurer de la sauvegarde de la version actuelle de la production.
  • Vérification de la version de DB restauré
  • Exécutez tous les correctifs (ceux-ci sont nommés par convention en utilisant major.minor.sql) qui sont plus tard que la version indiquée dans le tableau [Versions].

De cette façon, nous pouvons reconstruire toute la journée sans aucun problème, peu importe ce que le patch ne. Cela garantit également que lorsque nous ne déployons à la production, il n'y a aucun problème, puisque nous avons déjà déployé sur le 1000x db PRODUCTION au cours du développement.

Créé 27/08/2009 à 02:12
source utilisateur

voix
0

Avez-vous essayé Sql dynamique? Malheureusement, l'analyseur vérifie tout le script avant de l'exécuter, de sorte que toute colonne non valide arrêter l'exécution.

Créé 27/08/2009 à 02:22
source utilisateur

voix
1

Ok, je mal lu d'abord la question. :-)

Si vous modifiez les lignes d'insertion à partir de:

INSERT IGNORE  [foo] ([a], [b], [OrganizationId]) VALUES (N'a', N'b', N'1');

à:

exec('INSERT IGNORE  [foo] ([a], [b], [OrganizationId]) VALUES (''a'', ''b'', ''1'')');

Vous ne devriez pas avoir ce problème, étant donné que le « texte » SQL dans l'exécutif ne sera pas analysé jusqu'à ce que le exec () est en fait appelé.

Créé 27/08/2009 à 02:40
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more