Tsql T-SQL";“可重新运行”;数据库更新脚本-列删除
对于我们的SQL Server数据库,我们使用版本控制方案来跟踪模式更新。其想法是,您应该能够运行此脚本,将模式从任何以前的版本升级到当前版本。再次运行主脚本应该只执行最新的架构更新 脚本的结构如下所示: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
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()。谢谢,罗恩。我希望有一个替代方案来编辑一堆现有生成的脚本,但至少有一条前进的道路。