Tsql T-SQL";“可重新运行”;数据库更新脚本-列删除

Tsql T-SQL";“可重新运行”;数据库更新脚本-列删除,tsql,scripting,Tsql,Scripting,对于我们的SQL Server数据库,我们使用版本控制方案来跟踪模式更新。其想法是,您应该能够运行此脚本,将模式从任何以前的版本升级到当前版本。再次运行主脚本应该只执行最新的架构更新 脚本的结构如下所示: SELECT @Installed = InstallDate FROM SystemSchemaVersion WHERE Major=1 AND Minor=0 AND Patch=0 IF (@Installed IS NULL) BEGIN ... INSERT

对于我们的SQL Server数据库,我们使用版本控制方案来跟踪模式更新。其想法是,您应该能够运行此脚本,将模式从任何以前的版本升级到当前版本。再次运行主脚本应该只执行最新的架构更新

脚本的结构如下所示:

 SELECT @Installed = InstallDate FROM SystemSchemaVersion WHERE Major=1 AND Minor=0 AND Patch=0
 IF (@Installed IS NULL)
 BEGIN
    ...
    INSERT 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 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)
 SELECT @Installed = InstallDate FROM SystemSchemaVersion WHERE Major=1 AND Minor=0 AND Patch=0
 IF (@Installed IS NULL)
 BEGIN
    INSERT [foo] ([a], [b], [OrganizationId]) VALUES (N'a', N'b', N'1');
    INSERT 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 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)
这通常效果很好。然而,当模式更新删除前一个插入中包含的列时,我们遇到了一个问题;也就是说,我们有这样的东西:

 SELECT @Installed = InstallDate FROM SystemSchemaVersion WHERE Major=1 AND Minor=0 AND Patch=0
 IF (@Installed IS NULL)
 BEGIN
    ...
    INSERT 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 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)
 SELECT @Installed = InstallDate FROM SystemSchemaVersion WHERE Major=1 AND Minor=0 AND Patch=0
 IF (@Installed IS NULL)
 BEGIN
    INSERT [foo] ([a], [b], [OrganizationId]) VALUES (N'a', N'b', N'1');
    INSERT 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 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)
这在第一次执行时效果良好;执行版本1.0.1,并删除该列。但是,再次运行脚本会产生以下结果:

Msg 207, Level 16, State 1, Line 7118 Invalid column name 'OrganizationId'. 消息207,16级,状态1,第7118行 列名“OrganizationId”无效。 也就是说,即使版本1.0.0块中的INSERT没有被执行,它仍然被解析并生成无效列错误

对如何解决这个问题有什么建议吗?理想情况下,我希望用一个条件来保护INSERT,这样它甚至不会被解析,但这似乎不会发生。我可以在sp_ExecuteSql()调用中动态执行插入操作,但我不希望这样做(这需要大量改装)

谢谢--


--Andy

不幸的是,这与(在存储过程中)删除临时表然后重新创建它时遇到的问题类似。解析器会抱怨它已经存在,似乎没有意识到临时表已经被删除

如果您使用GO语句将其分开,那么您应该发现系统将在每个部分出现时重新评估它


Rob

我们使用几乎相同的设置来处理模式的版本控制

总的来说,你的方法是完全正确的。我们已经使用这种通用设置运行了好几年。基本上,为了处理任何破坏性或不兼容的模式更改,我们将这些补丁作为自动化CruiseControl.NET构建的一部分运行

所以我们的数据库构建看起来像这样

  • 从当前生产版本备份还原
  • 检查还原数据库的版本
  • 运行所有更新于[Versions]表中所示版本的修补程序(这些修补程序按约定使用major.minor.sql命名)

这样,无论补丁做什么,我们都可以全天重建,而不会出现任何问题。这也确保了当我们部署到生产环境中时不会出现问题,因为我们在开发过程中已经在生产数据库1000x上进行了部署。

您尝试过动态Sql吗?
遗憾的是,解析器将在运行脚本之前检查整个脚本,因此任何无效列都将停止执行。

好的,我一开始看错了问题。:-)

如果将插入行更改为:

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

您不应该有这个问题,因为exec中的SQL“文本”直到
实际上调用了exec()。

谢谢,罗恩。我希望有一个替代方案来编辑一堆现有生成的脚本,但至少有一条前进的道路。