SQL Server数据库版本控制


Answers:


179

马丁·福勒(Martin Fowler)在该主题上写了我最喜欢的文章,http://martinfowler.com/articles/evodb.html。我选择不像Alumb一样将架构转储置于版本控制之下,而其他人则建议,因为我想要一种简便的方法来升级生产数据库。

对于将只有一个生产数据库实例的Web应用程序,我使用两种技术:

数据库升级脚本

序列数据库升级脚本,其中包含将模式从版本N迁移到N + 1所必需的DDL。(这些在您的版本控制系统中。)_version_history_表,类似

create table VersionHistory (
    Version int primary key,
    UpgradeStart datetime not null,
    UpgradeEnd datetime
    );

每次运行与新版本相对应的升级脚本时,都会获得一个新条目。

这样可以确保轻松查看存在哪个版本的数据库架构,并且数据库升级脚本仅运行一次。同样,这些不是数据库转储。而是,每个脚本代表了从一个版本过渡到下一个版本所需的更改。它们是您应用于生产数据库以“升级”它的脚本。

开发人员沙箱同步

  1. 用于备份,清理和收缩生产数据库的脚本。每次升级到生产数据库后,请运行此命令。
  2. 用于在开发人员的工作站上还原(和调整,如有必要)备份的脚本。每个开发人员在每次升级到生产数据库后都运行此脚本。

一个警告:我的自动化测试针对的是架构正确但空的数据库,因此该建议将无法完全满足您的需求。


16
版本控制完整的模式脚本对于参考目的非常有用。例如,无法通过查看ALTER PROCEDURE语句来查看存储过程中到底发生了什么更改。
康斯坦丁

12
在运行新的升级脚本之后,转储(和版本化)完整的数据库模式是一种使信息也可用于构建/部署过程中的其他工具的好方法。同样,在脚本中具有完整的架构意味着能够“启动”一个新的数据库,而无需执行所有迁移步骤。还可以将当前版本与累积的先前版本进行比较。
mlibby

2
就是说您将升级脚本放在源代码管理中,而没有在其中放回退脚本?
AK

9
我习惯于维护完整的创建和删除脚本,以及用于更新现有数据库实例的增量脚本。两者都进入版本控制。增量脚本根据版本号命名。这样,使用更新脚本自动进行数据库修补很容易。
nikc.org 2010年

1
@ nikc.org的答案,以及用于自动化的提交后挂钩。
Silviu-Marian 2014年

45

Red Gate的SQL Compare产品不仅允许您进行对象级比较,并从中生成更改脚本,而且还允许您将数据库对象导出到按对象类型组织的文件夹层次结构中,并带有一个[objectname] .sql创建。这些目录中每个对象的脚本。对象类型层次结构是这样的:

\ Functions
\ Security
\ Security \ Roles
\ Security \ Schemas
\ Security \ Users
\ Stored Procedures
\ Tables

如果在进行更改后将脚本转储到相同的根目录,则可以使用它来更新SVN存储库,并分别保留每个对象的运行历史记录。


6
我们刚刚发布了SQL Source Control,它将您描述的SQL Compare行为集成到SSMS中,并链接到SVN和TFS。我为这个问题添加了一个单独的答案,更详细地描述了它的作用。red-gate.com/products/SQL_Source_Control/index.htm
David Atkinson,2010年

39

这是围绕发展的“难题”之一。据我所知,没有完美的解决方案。

如果只需要存储数据库结构而不是数据,则可以将数据库导出为SQL查询。(在企业管理器中:右键单击数据库->生成SQL脚本。我建议在选项选项卡上设置“为每个对象创建一个文件”),然后可以将这些文本文件提交到svn并利用svn的diff和日志记录功能。

我将其与使用几个参数并设置数据库的批处理脚本捆绑在一起。我还添加了一些其他查询,用于输入默认数据,例如用户类型和admin用户。(如果您想要更多有关此的信息,请发布一些内容,然后我可以将脚本放在可访问的位置)

如果还需要保留所有数据,我建议保留数据库的备份,并使用Redgate(http://www.red-gate.com/)产品进行比较。它们并不便宜,但它们值得每一分钱。


1
关于数据-您可以使用OffScale DataGrove保存整个数据库的版本(包括数据)。您以后可以使用它生成数据库的两个虚拟副本,可以将其与red-gate的产品进行比较。它还节省了您生成测试数据的需要-您只需保存数据库的版本以匹配不同的测试用例(再次是整个数据库的完整,虚拟副本)
Taichman 2011年

1
如果使用“每个对象一个文件”选项,如何确定运行数据库脚本的顺序?
杰米·基特森

@Taichman:DataGrove似乎不支持SQL Server,因此与该问题无关。
Neolisk '16

38

首先,您必须选择适合您的版本控制系统:

  • 集中式版本控制系统-一种标准系统,用户在使用文件之前/之后检出/签入文件,并将文件保存在单个中央服务器中

  • 分布式版本控制系统-一个正在克隆存储库的系统,每个克隆实际上都是该存储库的完整备份,因此,如果有任何服务器崩溃,则可以使用任何克隆的存储库来还原它。 ,您需要设置存储库,该存储库是每个版本控制系统的核心。下面的文章对此进行了说明:http : //solutioncenter.apexsql.com/sql-server-source-control-part-i-understanding -source-control-basics /

设置存储库后,在中央版本控制系统的情况下为工作文件夹,则可以阅读本文。它显示了如何使用以下方法在开发环境中设置源代码控制:

  • 通过MSSCCI提供程序的SQL Server Management Studio,

  • Visual Studio和SQL Server数据工具

  • 第三方工具ApexSQL源代码管理

24

在Red Gate,我们提供了SQL Source Control工具,该工具使用SQL Compare技术将您的数据库与TFS或SVN存储库链接。该工具已集成到SSMS中,使您可以照常工作,但现在可以提交对象。

对于基于迁移的方法(更适合于自动化部署),我们提供了SQL Change Automation(以前称为ReadyRoll),它可以作为Visual Studio项目创建和管理一组增量脚本。

在SQL Source Control中,可以指定静态数据表。这些作为INSERT语句存储在源代码管理中。

如果您在谈论测试数据,我们建议您使用工具或通过定义的部署后脚本生成测试数据,或者仅将生产备份还原到开发环境。


有趣的产品(市场差距很小),但是以“创建...”形式存储的增量让我感到恐惧。您如何分支/合并?
annakata

1
我们将对象定义存储为CREATE,但是如果您“获取最新信息”,或者例如使用SQL Compare Pro生成同步脚本,则会将这些脚本更改为适当的命令,例如ALTER。要进行分支或合并,您只需使用与当前相同的方式使用源代码控制系统。
大卫·阿特金森

此答案与两年前Dane的答案重复。
WonderWorker

这是一个不同的答案。SQL Compare不对数据库进行版本控制,而SQL Source Control是专门为此设计的。
大卫·阿特金森

21

您可能想看看Liquibase(http://www.liquibase.org/)。即使您不使用该工具本身,它也可以很好地处理数据库更改管理或重构的概念。


我们在单个分支上的5个分布式团队中使用Liquibase进行连续交付,并且效果很好。我们在许多不同的环境中安装了10多个数据库应用程序。我们使用它来管理架构,索引,分区,代码,查找数据,组和组权限。我们将其用于Oracle,Postgresql和MSSQL。
彼得·亨内尔

如果我根据介绍正确理解,它要求您知道一些专有的xml语言来声明对象而不是SQL?不是粉丝。
JDPeckham '17

19

为所有推荐RedGate工具的人+1,以及其他建议和警告。

SqlCompare还具有记录良好的API:例如,您可以编写一个控制台应用程序,该应用程序在签入时将您的源代码控制脚本文件夹与CI集成测试数据库同步,以便当有人从其脚本文件夹中检查对模式的更改时它会与匹配的应用程序代码更改一起自动部署。这有助于消除与忘记将本地数据库中的更改传播到共享开发数据库的开发人员之间的鸿沟(我认为,大约一半的人)。

需要注意的是,无论采用脚本解决方案还是其他方式,RedGate工具都足够平滑,以至于容易忘记抽象底层的SQL现实。如果重命名表中的所有列,则SqlCompare无法将旧列映射到新列,并且将删除表中的所有数据。它将生成警告,但我已经看到人们点击了该警告。我认为,这里有一个值得说明的一般要点:到目前为止,您只能使数据库版本控制和升级自动化-抽象非常容易泄漏。


因此,应该有一个系统来跟踪您要更改的列,并记住从旧列名到新列名的映射。
Silvercode

值得记住的是,对于含糊不清的数据库更改(因此需要“开发人员意图”的元素),基于迁移的解决方案是合适的解决方案。Redgate现在具有ReadyRoll,可以满足这种版本控制方法。
David Atkinson

15

我们使用DBGhost来管理我们的SQL数据库。然后,将脚本放入版本控制中以构建新数据库,然后它将构建新数据库或将任何现有数据库升级到版本控制中的架构。这样,您不必担心创建更改脚本(尽管您仍然可以这样做,例如,如果要更改列的数据类型并需要转换数据)。


我使用DbGhost已有10年了,从来没有让我失望过。他们提供的支持是首屈一指的
penderi 2010年

15

在VS 2010中,使用数据库项目。

  1. 编写数据库脚本
  2. 更改脚本或直接在数据库服务器上进行更改
  3. 使用数据>模式比较进行同步

提供了完美的数据库版本控制解决方案,并使同步数据库变得轻而易举。


2
是的,但是不幸的是,您必须记住每次都要“生成脚本”。如果直接更新数据库,则将失去为该增量生成更新脚本的能力。如果只有数据库项目将具有一些内置的版本控制功能。
2015年

13

用更改脚本将数据库脚本保存到版本控制中是一种好方法,这样您就可以升级拥有的任何一个数据库。另外,您可能希望保存不同版本的架构,以便可以创建完整的数据库而不必应用所有更改脚本。脚本的处理应该是自动化的,这样您就不必进行手动工作。

我认为为每个开发人员使用单独的数据库而不使用共享数据库很重要。这样,开发人员可以独立于其他开发人员创建测试案例和开发阶段。

自动化工具应该具有用于​​处理数据库元数据的方法,该方法可以告诉哪些数据库处于什么开发状态以及哪些表包含版本可控制的数据等等。


12

您还可以查看迁移解决方案。这些使您可以用C#代码指定数据库架构,并使用MSBuild上下滚动数据库版本。

我当前正在使用DbUp,并且运行良好。


11

您没有提及有关目标环境或约束的任何细节,因此这可能并不完全适用...但是,如果您正在寻找一种有效跟踪不断发展的数据库模式的方法,并且不会不利于使用Ruby,ActiveRecord的迁移就在您的小巷。

迁移以编程方式使用Ruby DSL定义数据库转换;每个转换都可以应用或(通常)回滚,从而使您可以在任何给定的时间点跳转到数据库模式的不同版本。可以像其他任何源代码一样,将定义这些转换的文件检入版本控制。

由于迁移是ActiveRecord的一部分,因此通常可以在全栈Rails应用程序中找到它们的用途。但是,您可以以最小的努力独立于Rails使用ActiveRecord。有关 Rails之外使用AR迁移的详细信息,请参见此处


10

每个数据库都应受源代码控制。缺少的是一种自动将所有数据库对象和“配置数据”脚本写入文件的工具,然后可以将其添加到任何源代码管理系统中。如果您使用的是SQL Server,那么我的解决方案在这里:http : //dbsourcetools.codeplex.com/。玩得开心。-内森。


9

这很简单。

  1. 基础项目准备就绪后,您必须创建完整的数据库脚本。该脚本已提交给SVN。这是第一个版本。

  2. 之后,所有开发人员都将创建更改脚本(ALTER ...,新表,存储过程等)。

  3. 当需要当前版本时,应执行所有新的更改脚本。

  4. 将应用程序发布到生产环境后,您可以返回到1(但它当然是连续的版本)。

Nant将帮助您执行那些更改脚本。:)

记住 有纪律的时候一切都很好。每次提交数据库更改时,代码中的相应功能也会被提交。


2
几年后,我说:使用FluentMigrator(或适用于您平台的类似工具)。
dariol

8

如果您的数据库很小,并且想要对整个数据库进行版本控制,那么此批处理脚本可能会有所帮助。它分离,压缩并检查Subversion中的MSSQL数据库MDF文件。

如果您主要是想对架构进行版本控制并且仅包含少量参考数据,则可以使用SubSonic Migrations进行处理。这样做的好处是您可以轻松地向上或向下迁移到任何特定版本。


8

为了使转储到源代码控制系统的速度更快一点,您可以使用sysobjects中的版本信息来查看自上次以来哪些对象已更改。

设置:在要逐步检查的每个数据库中创建一个表,以保存上次检查该数据库以来的版本信息(第一次运行时为空)。如果要重新扫描整个数据结构,请清除此表。

IF ISNULL(OBJECT_ID('last_run_sysversions'), 0) <> 0 DROP TABLE last_run_sysversions
CREATE TABLE last_run_sysversions (
    name varchar(128), 
    id int, base_schema_ver int,
    schema_ver int,
    type char(2)
)

正常运行模式:您可以从此sql中获取结果,并为您感兴趣的脚本生成sql脚本,然后将其放入您选择的源代码控件中。

IF ISNULL(OBJECT_ID('tempdb.dbo.#tmp'), 0) <> 0 DROP TABLE #tmp
CREATE TABLE #tmp (
    name varchar(128), 
    id int, base_schema_ver int,
    schema_ver int,
    type char(2)
)

SET NOCOUNT ON

-- Insert the values from the end of the last run into #tmp
INSERT #tmp (name, id, base_schema_ver, schema_ver, type) 
SELECT name, id, base_schema_ver, schema_ver, type FROM last_run_sysversions

DELETE last_run_sysversions
INSERT last_run_sysversions (name, id, base_schema_ver, schema_ver, type)
SELECT name, id, base_schema_ver, schema_ver, type FROM sysobjects

-- This next bit lists all differences to scripts.
SET NOCOUNT OFF

--Renamed.
SELECT 'renamed' AS ChangeType, t.name, o.name AS extra_info, 1 AS Priority
FROM sysobjects o INNER JOIN #tmp t ON o.id = t.id
WHERE o.name <> t.name /*COLLATE*/
AND o.type IN ('TR', 'P' ,'U' ,'V')
UNION 

--Changed (using alter)
SELECT 'changed' AS ChangeType, o.name /*COLLATE*/, 
       'altered' AS extra_info, 2 AS Priority
FROM sysobjects o INNER JOIN #tmp t ON o.id = t.id 
WHERE (
   o.base_schema_ver <> t.base_schema_ver
OR o.schema_ver      <> t.schema_ver
)
AND  o.type IN ('TR', 'P' ,'U' ,'V')
AND  o.name NOT IN ( SELECT oi.name 
         FROM sysobjects oi INNER JOIN #tmp ti ON oi.id = ti.id
         WHERE oi.name <> ti.name /*COLLATE*/
         AND oi.type IN ('TR', 'P' ,'U' ,'V')) 
UNION

--Changed (actually dropped and recreated [but not renamed])
SELECT 'changed' AS ChangeType, t.name, 'dropped' AS extra_info, 2 AS Priority
FROM #tmp t
WHERE    t.name IN ( SELECT ti.name /*COLLATE*/ FROM #tmp ti
         WHERE NOT EXISTS (SELECT * FROM sysobjects oi
                           WHERE oi.id = ti.id))
AND  t.name IN ( SELECT oi.name /*COLLATE*/ FROM sysobjects oi
         WHERE NOT EXISTS (SELECT * FROM #tmp ti
                           WHERE oi.id = ti.id)
         AND   oi.type  IN ('TR', 'P' ,'U' ,'V'))
UNION

--Deleted
SELECT 'deleted' AS ChangeType, t.name, '' AS extra_info, 0 AS Priority
FROM #tmp t
WHERE NOT EXISTS (SELECT * FROM sysobjects o
                  WHERE o.id = t.id)
AND t.name NOT IN (  SELECT oi.name /*COLLATE*/ FROM sysobjects oi
         WHERE NOT EXISTS (SELECT * FROM #tmp ti
                           WHERE oi.id = ti.id)
         AND   oi.type  IN ('TR', 'P' ,'U' ,'V'))
UNION

--Added
SELECT 'added' AS ChangeType, o.name /*COLLATE*/, '' AS extra_info, 4 AS Priority
FROM sysobjects o
WHERE NOT EXISTS (SELECT * FROM #tmp t
                  WHERE o.id = t.id)
AND      o.type  IN ('TR', 'P' ,'U' ,'V')
AND  o.name NOT IN ( SELECT ti.name /*COLLATE*/ FROM #tmp ti
         WHERE NOT EXISTS (SELECT * FROM sysobjects oi
                           WHERE oi.id = ti.id))
ORDER BY Priority ASC

注意:如果您在任何数据库中使用非标准排序规则,则将需要替换/* COLLATE */为数据库排序规则。即COLLATE Latin1_General_CI_AI


8

由于我们的应用程序必须跨多个RDBMS进行工作,因此我们使用与数据库无关的Torque格式(XML)将我们的架构定义存储在版本控制中。我们还按如下所示以XML格式对数据库的参考数据进行版本控制(其中“关系”是参考表之一):

  <Relationship RelationshipID="1" InternalName="Manager"/>
  <Relationship RelationshipID="2" InternalName="Delegate"/>
  etc.

然后,我们使用本地工具生成从数据库的版本X到版本X + 1所需的架构升级和参考数据升级脚本。


7

我们不存储数据库模式,而是将更改存储到数据库。我们要做的是存储模式更改,以便我们为数据库的任何版本构建更改脚本,并将其应用于客户的数据库。我编写了一个数据库实用程序应用程序,该应用程序随我们的主应用程序一起分发,该主应用程序可以读取该脚本并知道需要应用哪些更新。它还具有足够的智能,可以根据需要刷新视图和存储过程。


7

迁移到x64平台后,我们需要对SQL数据库进行版本控制,而旧版本因迁移而中断。我们编写了一个C#应用程序,该应用程序使用SQLDMO将所有SQL对象映射到一个文件夹:

                根
                    服务器名称
                       数据库名称
                          模式对象
                             数据库触发器*
                                .ddltrigger.sql
                             功能
                                ..function.sql
                             安全
                                的角色
                                   应用角色
                                      .approle.sql
                                   数据库角色
                                      .role.sql
                                模式*
                                   .schema.sql
                                用户数
                                   .user.sql
                             存储
                                全文目录*
                                   .fulltext.sql
                             存储过程
                                ..proc.sql
                             同义词*
                                .synonym.sql
                             桌子
                                ..table.sql
                                约束条件
                                   ... chkconst.sql
                                   ... defconst.sql
                                指标
                                   ... index.sql
                                按键
                                   ... fkey.sql
                                   ... pkey.sql
                                   ... ukey.sql
                                扳机
                                   ... trigger.sql
                             种类
                                用户定义的数据类型
                                   ..uddt.sql
                                XML模式集合*
                                   ..xmlschema.sql
                             观看次数
                                ..view.sql
                                指标
                                   ... index.sql
                                扳机
                                   ... trigger.sql

然后,应用程序会将新编写的版本与SVN中存储的版本进行比较,如果存在差异,它将更新SVN。我们确定每晚运行一次该进程就足够了,因为我们没有对SQL进行太多更改。它使我们能够跟踪对我们关心的所有对象的更改,并且还允许我们在出现严重问题时重建完整的架构。


噢,这将是很棒的公开可用。
克里斯·查拉巴鲁克

7

我前一阵子写了这个程序,http://sqlschemasourcectrl.codeplex.com/,它将根据需要扫描MSFT SQL数据库,并自动将对象(表,视图,proc,函数,sql设置)转储到SVN中。奇迹般有效。我将它与Unfuddle结合使用(这使我可以获得签到的警报)


6

典型的解决方案是根据需要转储数据库并备份那些文件。

根据您的开发平台,可能会有开源插件可用。滚动自己的代码来做到这一点通常是微不足道的。

注意:您可能想要备份数据库转储,而不是将其放入版本控制中。这些文件在版本控制中可能变得非常快,并导致整个源代码控制系统变慢(此刻我想起了CVS的恐怖故事)。


6

我们刚刚开始使用Team Foundation Server。如果您的数据库中等大小,则Visual Studio可以通过内置的比较,数据比较,数据库重构工具,数据库测试框架甚至数据生成工具来进行一些不错的项目集成。

但是,该模型不太适合大型或第三方数据库(用于加密对象)。因此,我们要做的是仅存储我们的自定义对象。Visual Studio / Team基础服务器可以很好地工作。

TFS数据库主管。博客

MS TFS网站


6

我同意ESV的答案,并且由于这个确切的原因,我不久前开始了一个小项目,以帮助将数据库更新维护在一个非常简单的文件中,然后可以将其长期保存为源代码。它允许对开发人员以及UAT和生产进行轻松更新。该工具适用于Sql Server和MySql。

一些项目功能:

  • 允许架构变更
  • 允许价值树人口
  • 允许插入单独的测试数据,例如。UAT
  • 允许回滚选项(非自动)
  • 维持对SQL Server和Mysql的支持
  • 能够使用一个简单的命令将现有数据库导入版本控制中(仅适用于sql server ...仍在mysql上运行)

该代码托管在Google代码上。请查看Google代码以获取更多信息

http://code.google.com/p/databaseversioncontrol/


5

不久前,我找到了一个VB bas模块,该模块使用DMO和VSS对象将整个数据库脚本化并写入VSS。我将其转换为VB脚本并将其发布到此处。您可以轻松地进行VSS调用并使用DMO东西来生成所有脚本,然后从调用VBScript来检入它们的同一批处理文件中调用SVN?

戴夫J


5

我还在数据库中使用通过数据库扩展属性系列过程存储的版本。我的应用程序具有每个版本步骤的脚本(即,从1.1到1.2)。部署后,它将查看当前版本,然后逐个运行脚本,直到到达最后一个应用程序版本。没有脚本具有直接的“最终”版本,即使在干净的数据库上进行部署也需要通过一系列升级步骤进行部署。

现在,我要补充的是,两天前我在MS校园中看到了有关新版和即将发布的VS DB版本的演示。演讲专门针对这个主题,我被淹没了。您绝对应该检查一下,新功能集中在将模式定义保留在T-SQL脚本(CREATE)中,运行时增量引擎将部署模式与定义的模式进行比较,并进行增量ALTER和与源代码集成的集成,直至并包括MSBUILD持续集成以实现自动构建删除。该放置将包含一个新的文件类型.dbschema文件,可以将其带到部署站点,并且命令行工具可以执行实际的“增量”并运行部署。我有一个关于此主题的博客条目,其中包含指向VSDE下载的链接,您应该检查一下它们:http://rusanu.com/2009/05/15/version-control-and-your-database/


5

这是一个非常老的问题,但是即使现在许多人仍在尝试解决这个问题。他们要做的就是研究Visual Studio数据库项目。没有这个,任何数据库开发都显得无能为力。从代码组织到部署再到版本控制,它简化了一切。


3

以我的经验,解决方案是双重的:

  1. 您需要处理开发人员在开发过程中对开发数据库所做的更改。

  2. 您需要在客户站点中处理数据库升级。

为了处理#1,您将需要一个强大的数据库差异/合并工具。最好的工具应该能够尽可能执行自动合并,同时允许您手动解决未处理的冲突。

完美的工具应该使用三向合并算法来处理合并操作,该算法考虑了THEIRS数据库和MINE数据库相对于BASE数据库所做的更改。

我写了一个商业工具,它为SQLite数据库提供了手动合并支持,而我目前正在添加对SQLite的三向合并算法的支持。在以下位置查看 http://www.sqlitecompare.com上进行

为了处理#2,您将需要一个升级框架。

基本思想是开发一个自动升级框架,该框架知道如何从现有的SQL模式升级到较新的SQL模式,并可以为每个现有的数据库安装构建升级路径。

http://www.codeproject.com/KB/database/sqlite_upgrade.aspx中查看有关该主题的文章以大致了解我在说什么。

祝好运

利隆·列维(Liron Levi)


3

请访问DBGhost http://www.innovartis.co.uk/。我已经以自动化方式使用了2年,效果很好。它允许我们的数据库构建发生得像Java或C生成一样发生,除了数据库。你知道我的意思。


2

我建议使用比较工具来为您的数据库临时创建一个版本控制系统。xSQL Schema ComparexSQL Data Compare是一个很好的选择。

现在,如果您的目标是仅对数据库的架构进行版本控制,则只需使用xSQL架构比较生成架构的xSQL快照并将这些文件添加到版本控制中。然后,要还原或更新到特定版本,只需将数据库的当前版本与目标版本的快照进行比较。

las,如果您也想让数据受版本控制,则可以使用xSQL数据比较为数据库生成更改脚本,并将.sql文件添加到版本控制中。然后,您可以执行这些脚本以还原/更新到所需的任何版本。请记住,对于“还原”功能,您需要生成更改脚本,该脚本在执行时将使版本3与版本2相同;对于“更新”功能,您需要生成相反的更改脚本。

最后,借助一些基本的批处理编程技巧,您可以使用xSQL Schema Compare和xSQL Data Compare的命令行版本来自动化整个过程。

免责声明:我隶属于xSQL。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.