sql-server - 如何在 SSDT 项目中包含自定义数据迁移和静态/引用数据?

标签 sql-server data-migration sql-server-data-tools

我们有一个中等规模的 SSDT 项目(约 100 个表),部署到数十个不同的数据库实例。作为构建过程的一部分,我们生成一个 .dacpac 文件,然后当我们准备好升级数据库时,我们生成一个发布脚本并针对数据库运行它。一些数据库实例在不同时间升级,因此我们为这些升级和版本控制制定结构化流程非常重要。

大多数生成的迁移脚本都会删除并(重新)创建过程、函数、索引并执行任何结构更改,以及部署后脚本中包含的一些数据脚本。我想知道如何在项目中最好地构建这两个与数据相关的项目:

  1. 版本之间需要自定义数据迁移

  2. 静态或引用数据

版本之间需要自定义数据迁移

有时,我们希望在升级过程中执行一次性数据迁移,但我不确定将其合并到我们的 SSDT 项目中的最佳方法。例如,最近我添加了一个新的位列dbo.Charge.HasComments来包含基于另一个表的(冗余)派生数据,并将通过触发器保持同步。令人烦恼但必要的性能改进(仅在仔细考虑和测量后添加)。作为升级的一部分,SSDT 生成的发布脚本将包含必要的 ALTER TABLE 和 CREATE TRIGGER 语句,但我还想根据另一个表中的数据更新此列:

update dbo.Charge 
set HasComments = 1 
where exists ( select * 
               from dbo.ChargeComment 
               where ChargeComment.ChargeId = Charge.ChargeId ) 
and HasComments = 0 

将此数据迁移脚本包含在我的 SSDT 项目中的最佳方法是什么?

目前,我将每种类型的迁移都放在部署后脚本中包含的单独文件中,因此我的部署后脚本最终如下所示:

-- data migrations
:r "data migration\Update dbo.Charge.HasComments if never populated.sql"
go
:r "data migration\Update some other new table or column.sql"
go

这是正确的方法吗?还是有某种方法可以更好地与 SSDT 及其版本跟踪结合起来,这样当 SSDT 发布针对已经处于某个状态的数据库运行时,这些脚本甚至不会运行更新的版本。我可以拥有自己的表来跟踪已运行的迁移,但如果有执行此操作的标准方法,我宁愿不自行滚动。

静态或引用数据

一些数据库表包含我们所说的静态或引用数据,例如可能的时区、设置类型、货币、各种“类型”表等的列表。目前,我们通过为每个表创建一个单独的脚本(作为部署后脚本的一部分运行)来填充这些内容。每个静态数据脚本将所有“正确”的静态数据插入到表变量中,然后根据需要插入/更新/删除静态数据表。根据表的不同,可能只适合插入或只适合插入和删除,但不适用于更新现有记录。所以每个脚本看起来都是这样的:

-- table listing all the correct static data
declare @working_data table (...)

-- add all the static data that should exist into the working table
insert into @working_data (...) select null, null null where 1=0
union all select 'row1 col1 value', 'col2 value', etc...
union all select 'row2 col1 value', 'col2 value', etc...
...

-- insert any missing records in the live table
insert into staticDataTableX (...)
select * from @working_data
where not exists ( select * from staticDataTableX
                   where [... primary key join on @working_data...] )

-- update any columns that should be updated
update staticDataTableX
set ...
from staticDataTableX
inner join @working_data on [... primary key join on @working_data...]

-- delete any records, if appropriate with this sort of static data
delete from staticDataTableX
where not exists ( select * from staticDataTableX
                   where [... primary key join on @working_data...] )

然后我的部署后脚本有一个如下部分:

-- static data. each script adds any missing static/reference data:
:r "static_data\settings.sql"
go
:r "static_data\other_static_data.sql"
go
:r "static_data\more_static_data.sql"
go

是否有更好或更传统的方法来构建此类静态数据脚本作为 SSDT 项目的一部分?

最佳答案

要跟踪字段是否已初始化,请尝试在执行初始化时添加扩展属性(它也可用于确定是否需要初始化):

要添加扩展属性:

EXEC sys.sp_addextendedproperty 
@name = N'EP_Charge_HasComments', 
@value = N'Initialized', 
@level0type = N'SCHEMA', @level0name = dbo, 
@level1type = N'TABLE',  @level1name = Charge,
@level2type = N'COLUMN', @level2name = HasComments;

要检查扩展属性:

SELECT objtype, objname, name, value
FROM fn_listextendedproperty (NULL, 
    'SCHEMA', 'dbo', 
    'TABLE', 'Charge', 
    'COLUMN', 'HasComments');

对于引用数据,请尝试使用 MERGE。它比您使用的三组查询干净得多。

MERGE INTO staticDataTableX AS Target
USING (
VALUES  
        ('row1_UniqueID', 'row1_col1_value', 'col2_value'),
        ('row2_UniqueID', 'row2_col1_value', 'col2_value'),
        ('row3_UniqueID', 'row3_col1_value', 'col2_value'),
        ('row4_UniqueID', 'row4_col1_value', 'col2_value')


    ) AS Source (TableXID,  col1, col2)
        ON Target.TableXID = Source.TableXID
WHEN MATCHED THEN
   UPDATE SET 
        Target.col1 = Source.col1,  
        Target.col2 = Source.col2  

WHEN NOT MATCHED BY TARGET THEN
   INSERT (TableXID,  col1, col2)
   VALUES (Source.TableXID,  Source.col1, Source.col2)

WHEN NOT MATCHED BY SOURCE THEN
    DELETE; 

关于sql-server - 如何在 SSDT 项目中包含自定义数据迁移和静态/引用数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22746200/

相关文章:

c# - 在数据库中存储第三方服务登录名/密码

sql - 如何使用 SQL Server 2012 窗口函数计算指数移动平均值

sql - 是否可以用 SQL DML 替换整个节点?

ios - iOS 应用程序数据库中的 10 个核心数据表,如何将它们全部复制到一个新的单个表中?

drupal - 迁移节点引用

sql-server - 重命名表导致 CREATE 语句而不是 ALTER

msbuild - 通过 Web 部署来部署 SSDT

sql-server - 我应该使用 EXISTS 还是 IN

java - 在多台计算机上管理 SQL

visual-studio-2012 - SQL 数据库项目 : build different scripts depending on build configuration