我们的(ASP.NET)软件使用MSSQL数据库。我们会定期发布我们软件的新版本,有时会对我们的数据库进行更改。
目前,我们根据以前的版本和新版本为每个更新数据库的版本编写SQL更新脚本。当我们必须更新旧客户端时,这会变得很烦人,必须按顺序应用每个SQL更新脚本,直到它再次更新为止。我正试图找到一种不必这样做的方法,我可以只有一个SQL脚本,无论旧数据库是什么版本(或者即使它没有),它总会将数据库更新到新版本存在)。
我能想到的唯一方法是为每个表和列以及存储过程提供大量的“IF NOT EXISTS”。有没有更好的方法(不丢失数据库中的数据)?
P.S。我发现很难谷歌这个(不知道如何描述),因此这个问题。
答案 0 :(得分:1)
我认为在数据库中存储架构更新版本是有意义的。更新脚本将读取当前版本并基于此,让它按顺序执行所有先前的更新脚本,直到它是最新的。这将是一种前瞻性方法,因为旧的模式版本不会存储版本号。如果您可以确定每个先前架构更新的区别特征 - 那么它仍然可以工作。因此,您的更新逻辑必须位于脚本中,并且您的发布包必须附带所有以前的更新sql文件。
答案 1 :(得分:1)
我所做的是维护每个数据库版本的开发副本,因为它存在于特定版本,并使用redgate工具生成我需要的脚本。如果我需要一个脚本从V1.3升级到V2.5,我选择这两个数据库并生成脚本。
您可以在一个脚本中完成所有操作,但您需要手动完成。为什么不使用像redgate这样的工具来简化你的生活呢?
http://www.red-gate.com/products/sql-development/sql-compare/
答案 2 :(得分:0)
您可以使用Red Gate的SQL Compare在数据库的每个版本之间生成一个diff脚本,即
v1 to v2 diff script
v1 to v3 diff script
v1 to v4 diff script
v2 to v3
v2 to v4
v3 to v4
这将涵盖所有更改,包括代码和表更改 - 如果您具有作为升级更新的“静态”值,它还可能包括数据更改 - 您需要他们的sql数据比较产品。
答案 3 :(得分:0)
虽然使用IF NOT EXISTS等使每个DDL脚本“可重新运行”是一种很好的做法,但我可以看到这种方法最终会变得混乱和繁琐。运行数据转换脚本时,它也会变得特别棘手。
我一直采用的方法是按顺序编号每个脚本并将它们存储在某处并跟踪上次运行脚本的ID;该ID是您的DBVersion。 DBVersion编号存储在DB的设置或版本表中。
剩下的就是有一些过程来比较DBVersion值和脚本表(或文件,字典或其他)的MAX(id)
CREATE TABLE DBVer
(
DBVer INT PRIMARY KEY CLUSTERED
)
INSERT INTO DBVer(DBVer)
SELECT 1
CREATE TABLE DBScripts
(
ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
Script NVARCHAR(MAX)
)
CREATE PROC UpdateDB
AS
DECLARE @i INT,
@max INT,
@SQL NVARCHAR(MAX)
SELECT @max = MAX(ID), @i = MAX(DBVER)
FROM DBScripts
CROSS JOIN DBVer --only ever one row in here but make sure!
if @i>@max
RETURN --no updates, let exit early
WHILE @i <= @max --loop through and apply new scripts
BEGIN
SELECT @SQL = Script
FROM DBScripts
WHERE ID = @i
EXEC sp_executesql @statement = @SQL
SET @i = @i + 1
END
UPDATE DBVer SET DBVer = @i --this can also be in the loop
GO
这不是一个完整的解决方案,但你会得到一般的想法。
需要考虑的事项包括调用更新的位置,如果100个客户端中的每个客户端在启动时调用updateDB,则可能值得使用一些锁定或其他方法来管理潜在的竞争条件。在交易中包装所有内容也是值得的。 DDL可以回滚,但您也可以通过大的更改快速填充日志。