将Sql更改部署到客户数据库(更改的表,函数,...)

时间:2016-10-04 13:49:48

标签: mysql sql sql-server oracle postgresql

我正在开发一个在客户系统上使用数据库(PostgreSQL,MySQL,Oracle或MSSQL)的应用程序。

因此,我需要为每个新版本执行数据库更新。

我目前处于概念阶段,并没有在生产中运行。

所有DDL语句都在脚本文件中。

结构如下:

tables\employees.sql
       customers.sql
       orders.sql

这些脚本也在版本控制中,可用于从拉伸构建数据库。

当然,将来某些时候会对这些表格进行更改。

例如,表员工的创建方式如下:

CREATE TABLE if not exists employees
(
    EmployeeId      serial,
    FirstName       text,

    PRIMARY KEY (EmployeeId)
);

在将来的版本中,表格会被扩展:

ALTER TABLE employees ADD COLUMN address varchar(30);

在我的研究中,我找到了这个例子:https://stackoverflow.com/posts/115422/revisions。 版本号用于执行特定更改。

我喜欢这个概念,我的想法是实现类似的东西。 但我没有考虑系统版本号,而是考虑为每个表引入一个版本。

创建员工表时,会获得版本号1.随着该表的每次更改,版本号增加1.添加地址列后(更改上面的声明)表格版本为2。

每个表更改都会发生在嵌套事务中,如下所示:

BEGIN TRANSACTION;

UPDATE employees SET Version = 2;

ALTER TABLE employees
     ALTER TABLE employees ADD COLUMN address varchar(30);

END TRANSACTION;

如果表版本低于当前表格版本,则将回滚该事务。 该逻辑的实现尚未完成。

好处是表的所有更改都在表的脚本文件本身内,并且初始语句始终是最新的。

例如,首次创建员工表时,它将如下所示:

employees.sql

CREATE TABLE if not exists employees
(
    EmployeeId      serial,
    FirstName       text,

    Version         int       default 1 not null,

    PRIMARY KEY (EmployeeId)
);

经过一些更改后,它看起来像这样:

employees.sql

CREATE TABLE if not exists employees
(
    EmployeeId      serial,
    FirstName       varchar(100),
    address         varchar(80),

    Version         int       default 3 not null, -- notice the 3 

    PRIMARY KEY (EmployeeId)
);

-- First Change
BEGIN TRANSACTION;

UPDATE employees SET Version = 2;

ALTER TABLE employees
    ALTER TABLE employees ADD COLUMN address varchar(30);

END TRANSACTION;

-- Second Change
BEGIN TRANSACTION;

UPDATE employees SET Version = 3;

ALTER TABLE employees
    ALTER COLUMN address TYPE varchar(80),
    ALTER COLUMN FirstName TYPE varchar(100);

END TRANSACTION;

这个概念是否可以接受,还是我在这里重新发明轮子?

1 个答案:

答案 0 :(得分:2)

我认为设置每个表的版本号是过度的。此外,它使DB和应用程序的管理变得复杂。我建议您为DB_VersionNumber添加一个新表,并在此表中为每次升级添加一行。我一直在做的是: 1)在DB中为数据库版本创建一个表(步骤) 2)如果表中不存在,则创建一个检查此表并运行数据库升级步骤的SP,否则跳过该步骤。 3)对于每个数据库更改,在升级脚本文件中添加一个步骤(您已创建并添加到源代码管理中)。

Here is the table and the SP:

IF OBJECT_ID (N'DB_Version', N'U') IS  NULL
Begin
    CREATE TABLE [DB_Version](
        [VersionNumber] [decimal](18, 2) NOT NULL,
        [CommitTimestamp] [smalldatetime] NOT NULL
    ) ON [PRIMARY]


    ALTER TABLE DB_Version
    ADD CONSTRAINT UQ_VersionNumber UNIQUE (VersionNumber); 
End

IF OBJECT_ID ( 'NewDBStep', 'P' ) IS NULL 
begin
    Exec ('
    -- ============================================
    -- Description: Applies a new DB upgrade step to the current DB
    -- =============================================
    CREATE PROCEDURE NewDBStep 
        @dbVersion [decimal](18, 2),
        @script    varchar (max)
    AS
    BEGIN
        If not exists (select 1 from DB_Version Where VersionNumber = @dbVersion)
        Begin
            -- SET NOCOUNT ON added to prevent extra result sets from
            -- interfering with SELECT statements.
            SET NOCOUNT ON;

            BEGIN TRY
                Begin tran
                Exec (@script)

                Insert into DB_Version (VersionNumber, CommitTimestamp) Values (@dbVersion, CURRENT_TIMESTAMP);
                Commit tran

                Print ''Applied upgrade step '' + Cast ( @dbVersion as nvarchar(20))
            END TRY
            BEGIN CATCH
                Rollback tran
                Print ''Failed to apply step '' + Cast ( @dbVersion as nvarchar(20))
                Select ERROR_NUMBER() AS ErrorNumber
                ,ERROR_SEVERITY() AS ErrorSeverity
                ,ERROR_STATE() AS ErrorState
                ,ERROR_PROCEDURE() AS ErrorProcedure
                ,ERROR_LINE() AS ErrorLine
                ,ERROR_MESSAGE() AS ErrorMessage;
            END CATCH
        End
    END ') ;
End

然后,通过调用SP来应用您的升级(关键是您必须为每个升级脚本分配一个唯一的步骤编号:

----------------  Add the new steps here
-- Step: 0.01 
-- Adding the MyTableName table if it does not exist. 
Exec NewDBStep 0.01, '
IF OBJECT_ID (N''MyTableName'', N''U'') IS  NULL
Begin
    CREATE TABLE [MyTableName](
        [Id] [int] IDENTITY(1,1) NOT NULL,
        [UserType] [nvarchar](20) NULL,
    PRIMARY KEY CLUSTERED 
    (
        [Id] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
End
'
Exec NewDBStep 1.00, '
-- Some other DDL script 
'