【问题标题】:SQL version control methodologySQL 版本控制方法
【发布时间】:2025-12-17 11:00:02
【问题描述】:

关于 SQL 的版本控制和网络上的大量资源有几个关于 SO 的问题,但我找不到完全涵盖我正在尝试做的事情。

首先,我在这里谈论的是一种方法。我熟悉那里的各种源代码控制应用程序,我熟悉 Red Gate 的 SQL 比较等工具,并且我知道如何编写一个应用程序来自动签入和签出我的源代码控制系统。如果有一种工具对提供全新的方法特别有用,或者具有有用且不常见的功能,那就太好了,但是对于上面提到的任务,我已经准备好了。

我试图满足的要求是:

  • 数据库架构和查找表数据已版本化
  • 用于对较大表进行数据修复的 DML 脚本已版本化
  • 服务器可以从版本 N 升级到版本 N + X,其中 X 可能不总是 1
  • 代码不会在版本控制系统中重复 - 例如,如果我向表中添加一列,我不想确保更改同时出现在创建脚本和更改脚本中李>
  • 系统需要支持应用程序不同版本的多个客户端(尝试将它们全部升级到 1 或 2 个版本,但还没有)

一些组织在他们的版本控制中保留增量更改脚本,并且要从版本 N 到 N + 3,您必须运行 N->N+1 然后 N+1->N+2 然后 N+2- 的脚本>N+3。其中一些脚本可能是重复的(例如,添加了一个列,但随后又对其进行了更改以更改数据类型)。我们试图避免这种重复,因为一些客户端数据库可能非常大,因此这些更改可能需要比必要更长的时间。

一些组织只会在每个版本级别保留完整的数据库构建脚本,然后使用 SQL Compare 等工具将数据库升级到其中一个版本。这里的问题是混合 DML 脚本可能是个问题。想象一个场景,我添加一个列,使用 DML 脚本填充该列,然后在更高版本中更改该列名称。

也许有一些混合解决方案?也许我只是要求太多?任何想法或建议将不胜感激。

如果版主认为这更适合作为社区 wiki,请告诉我。

谢谢!

【问题讨论】:

  • 不知道你有没有看到这个,但我得到了一些合理的答案:*.com/questions/2401229/…
  • 这有帮助吗? msmvps.com/blogs/deborahk/archive/2010/05/02/…注意,文章底部还有更多链接。
  • @Paddy - 感谢您的链接。 pdc 有一个很好的解决方案,与我们正在考虑的解决方案相匹配,但是脚本创建任务外包给了印度(不是我的选择),而且那里的专业知识有限,所以一些更复杂的代码可能是个问题。不过,它现在仍在桌面上。

标签: sql version-control migration


【解决方案1】:

我为此苦苦挣扎了几年,最近才采用了一种似乎效果很好的策略。我赖以生存的要点:

  • 数据库不需要独立于应用程序进行版本控制
  • 所有数据库更新脚本都应该是幂等的

因此,我不再创建任何类型的版本表。我只是将更改添加到可在任何给定时间应用的编号序列 .sql 文件,而不会损坏数据库。如果它使事情变得更容易,我将为应用程序编写一个简单的安装程序屏幕,以允许管理员随时运行这些脚本。

当然,这种方法确实对数据库设计提出了一些要求:

  • 所有架构更改都通过脚本完成 - 没有 GUI 工作。
  • 必须格外小心,以确保所有键、约束等都已命名,以便以后的更新脚本可以在必要时引用它们。
  • 所有更新脚本都应检查现有条件。

近期项目的示例:

001.sql:

if object_id(N'dbo.Registrations') is null 
begin
    create table dbo.Registrations
    (
        [Id]                    uniqueidentifier not null,
        [SourceA]               nvarchar(50)     null,
        [SourceB]               nvarchar(50)     null,
        [Title]                 nvarchar(50)     not null,
        [Occupation]            nvarchar(50)     not null,
        [EmailAddress]          nvarchar(100)    not null,
        [FirstName]             nvarchar(50)     not null,
        [LastName]              nvarchar(50)     not null,
        [ClinicName]            nvarchar(200)    not null,
        [ClinicAddress]         nvarchar(50)     not null,
        [ClinicCity]            nvarchar(50)     not null,
        [ClinicState]           nchar(2)         not null,
        [ClinicPostal]          nvarchar(10)     not null,
        [ClinicPhoneNumber]     nvarchar(10)     not null,
        [ClinicPhoneExtension]  nvarchar(10)     not null,
        [ClinicFaxNumber]       nvarchar(10)     not null,
        [NumberOfVets]          int              not null,  
        [IpAddress]             nvarchar(20)     not null,
        [MailOptIn]             bit              not null,
        [EmailOptIn]            bit              not null,
        [Created]               datetime         not null,
        [Modified]              datetime         not null,
        [Deleted]               datetime         null
    );
end

if not exists(select 1 from information_schema.table_constraints where constraint_name = 'pk_registrations')
    alter table dbo.Registrations add
        constraint pk_registrations primary key nonclustered (Id);

if not exists (select 1 from sysindexes where [name] = 'ix_registrations_created')
    create clustered index ix_registrations_created
        on dbo.Registrations(Created);

if not exists (select 1 from sysindexes where [name] = 'ix_registrations_email')
    create index ix_registrations_email
        on dbo.Registrations(EmailAddress);

if not exists (select 1 from sysindexes where [name] = 'ix_registrations_email')
    create index ix_registrations_name_and_clinic
        on dbo.Registrations (FirstName,
                              LastName,
                              ClinicName);

002.sql

/**********************************************************************
  The original schema allowed null for these columns, but we don't want
  that, so update existing nulls and change the columns to disallow 
  null values
 *********************************************************************/

update dbo.Registrations set SourceA = '' where SourceA is null;
update dbo.Registrations set SourceB = '' where SourceB is null;
alter table dbo.Registrations alter column SourceA nvarchar(50) not null;
alter table dbo.Registrations alter column SourceB nvarchar(50) not null;

/**********************************************************************
  The client wanted to modify the signup form to include a fax opt-in
 *********************************************************************/

if not exists 
(
    select 1 
      from information_schema.columns
     where table_schema = 'dbo'
       and table_name   = 'Registrations'
       and column_name  = 'FaxOptIn'
)
alter table dbo.Registrations 
    add FaxOptIn bit null 
        constraint df_registrations_faxoptin default 0;

003.sql、004.sql 等...

在任何给定时间,我都可以在任何状态下针对数据库运行整个系列的脚本,并且知道事情将立即与当前版本的应用程序同步。因为一切都是脚本化的,所以构建一个简单的安装程序来执行此操作要容易得多,并且将架构更改添加到源代码控制中完全没有问题。

【讨论】:

  • 谢谢。这类似于在 Paddy 的链接中发布的“pdc”。这就是我过去一天一直在努力卖的东西。这里的一些人仍然坚持使用带有额外元数据的模型数据库的想法,然后使用比较工具和其他工具,但也许我可以影响他们。我的方法实际上仍然尽可能地将单个对象的脚本保留在一个文件中,并且当发生新的更改时,它们会进入该文件,而不是不断添加新脚本。版本之间的排序是唯一的挑战,我想我也有解决方案。
【解决方案2】:

您有一套相当严格的要求,我不确定您是否会找到可以检查所有框的东西,尤其是多个并发模式和智能版本控制。

我读过的关于这种拟合的最有前途的工具是Liquibase
以下是一些附加链接:

【讨论】:

  • 感谢您的建议。是的,绝对是一份严格的要求清单,但我充满希望 :) 我会看看 LiquiBase 能做什么。
【解决方案3】:

是的,您要求的很多,但它们都是非常中肯的!在 Red Gate,我们正在通过我们的 SQL 源代码控制 SSMS 扩展实现完整的数据库开发解决方案,我们也面临着类似的挑战。

http://www.red-gate.com/products/SQL_Source_Control/index.htm

对于即将发布的版本,我们将完全支持架构更改,并通过我们的 SQL 数据比较工具间接支持静态数据。所有更改都保存为创建脚本,但当您更新或部署到数据库时,该工具将确保将更改作为 ALTER 或 CREATE 正确应用。

目前还没有简单解决方案的最具挑战性的需求是版本管理和部署,您对此进行了非常清楚的描述。如果您对架构和数据进行复杂的更改,则可能不可避免地会构建手工制作的迁移脚本以在两个相邻版本之间进行切换,因为并非所有“意图”总是与较新版本一起保存。列重命名就是一个很好的例子。解决方案可能是设计一个保存意图的系统,或者如果这太复杂,允许用户提供自定义脚本来执行复杂的更改。某种版本管理框架会管理这些并“神奇地”从两个任意版本构建部署脚本。

【讨论】:

    【解决方案4】:

    对于此类问题,请使用 Visual Studio Team System 2008 对您的 sql 数据库进行版本控制。

    在 tsf 中没有。的功能类似

    • 数据比较
    • 架构比较
    • 版本控制

    关于数据库版本控制:http://www.codinghorror.com/blog/2006/12/is-your-database-under-version-control.html 更多细节检查:http://msdn.microsoft.com/en-us/library/ms364062(VS.80).aspx

    【讨论】:

      【解决方案5】:

      我们使用 SQL Examiner 将数据库架构保持在版本控制之下。我也尝试过 VS2010,但我认为 VS 方法对于中小型项目来说太复杂了。使用 SQL Examiner,我主要使用 SSMS 并使用 SQL Examiner 签入 SVN 的更新(也支持 TFS 和 SourceSafe,但我从未尝试过)。

      这里是 SQL Examiner 方法的描述:How to get your database under version control

      【讨论】:

      • 感谢您的建议。不幸的是,这只适用于将脚本放入源代码控制系统。我的问题是在部署时 - 在使用不同版本软件的许多客户之间实现自动化。
      • SQL Examiner 将存储在 SVN 中的数据库脚本与目标数据库进行比较,并生成架构迁移脚本。此外,您可以将 SVN 中的版本 10 与 SVN 中的版本 12 进行比较,并生成脚本以将架构从版本 10 迁移到版本 12。
      【解决方案6】:

      试试 DBSourceTools。 (http://dbsourcetools.codeplex.com)
      它是开源的,专门设计用于编写整个数据库的脚本 - 表、视图、procs 到磁盘,然后通过部署目标重新创建该数据库。
      您可以编写所有数据的脚本,或者只指定要为哪些表编写脚本数据。
      此外,您可以压缩结果以进行分发。
      我们使用它来控制数据库的源代码,并测试新版本的更新补丁。
      在后端,它围绕 SMO 构建,因此支持 SQL 2000、2005 和 2008。
      DBDiff 已集成,允许进行模式比较。
      玩得开心, - 内森。

      【讨论】: