简体   繁体   English

如何在SSDT项目中包括自定义数据迁移和静态/参考数据?

[英]How to include custom data migrations and static/reference data in an SSDT project?

We have a moderately-sized SSDT project (~100 tables) that's deployed to dozens of different database instances. 我们有一个中等大小的SSDT项目(约100个表),已部署到许多不同的数据库实例中。 As part of our build process we generate a .dacpac file and then when we're ready to upgrade a database we generate a publish script and run it against the database. 作为构建过程的一部分,我们生成一个.dacpac文件,然后在准备升级数据库时,我们生成一个发布脚本并针对该数据库运行它。 Some db instances are upgraded at different times so it's important that we have a structured process for these upgrades and versioning. 一些数据库实例在不同的时间进行升级,因此对于这些升级和版本控制,我们有一个结构化的过程很重要。

Most of the generated migration script is dropping and (re)creating procs, functions, indexes and performing any structural changes, plus some data scripts included in a Post-Deployment script. 生成的大多数迁移脚本都将删除和(重新)创建proc,函数,索引并执行任何结构更改,以及部署后脚本中包含的一些数据脚本。 It's these two data-related items I'd like to know how best to structure within the project: 我想了解这两个与数据相关的项目如何在项目中最好地组织:

  1. Custom data migrations needed between versions 版本之间需要自定义数据迁移

  2. Static or reference data 静态或参考数据

Custom data migrations needed between versions 版本之间需要自定义数据迁移

Sometimes we want to perform a one-off data migration as part of an upgrade and I'm not sure the best way to incorporate this into our SSDT project. 有时,我们希望在升级过程中执行一次性数据迁移,但我不确定将其整合到我们的SSDT项目中的最佳方法。 For example, recently I added a new bit column dbo.Charge.HasComments to contain (redundant) derived data based on another table and will be kept in sync via triggers. 例如,最近我添加了一个新的位列dbo.Charge.HasComments以包含基于另一个表的(冗余)派生数据,并将通过触发器保持同步。 An annoying but necessary performance improvement (only added after careful consideration & measurement). 烦人但必要的性能改进(仅在经过仔细考虑和测量后才添加)。 As part of the upgrade the SSDT-generated Publish script will contain the necessary ALTER TABLE and CREATE TRIGGER statements, but I also want to update this column based on data in another table: 作为升级的一部分,SSDT生成的发布脚本将包含必要的ALTER TABLECREATE TRIGGER语句,但是我还想根据另一个表中的数据更新此列:

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

What's the best way to include this data migration script in my SSDT project? 在我的SSDT项目中包括此数据迁移脚本的最佳方法是什么?

Currently I have each of these types of migrations in a separate file that's included in the Post-Deployment script, so my Post-Deployment script ends up looking like this: 目前,我在部署后脚本中包含的单独文件中拥有每种类型的迁移,因此我的部署后脚本最终看起来像这样:

-- 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

Is this the right way to do it, or is there some way to tie in with SSDT and its version tracking better, so those scripts aren't even run when the SSDT Publish is being run against a database that's already at a more recent version. 这是正确的方法,还是有某种方法可以更好地与SSDT配合使用,并且可以更好地跟踪其版本,因此,当针对已经有较新版本的数据库运行SSDT Publish时,这些脚本甚至都不会运行。 I could have my own table for tracking which migrations have been run, but would prefer not to roll-my-own if there's a standard way of doing this stuff. 我可以拥有自己的表来跟踪已运行的迁移,但是如果有标准的方法可以执行此操作,则不愿自己动手。

Static or reference data 静态或参考数据

Some of the database tables contain what we call static or reference data, eg list of possible timezones, setting types, currencies, various 'type' tables etc. Currently we populate these by having a separate script for each table that is run as part of the Post-Deployment script. 一些数据库表包含我们称为静态或参考数据的数据,例如,可能的时区列表,设置类型,货币,各种“类型”表等。当前,我们通过为作为表的一部分运行的每个表使用单独的脚本来填充这些数据。部署后脚本。 Each static data script inserts all the 'correct' static data into a table variable and then inserts/updates/deletes the static data table as needed. 每个静态数据脚本都将所有“正确的”静态数据插入表变量,然后根据需要插入/更新/删除静态数据表。 Depending on the table it might be appropriate only to insert or only insert and delete but not to update existing records. 根据表的不同,可能只适合插入或仅适合插入和删除,而不适合更新现有记录。 So each script looks something like this: 因此,每个脚本如下所示:

-- 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...] )

and then my Post-Deployment script has a section like this: 然后我的“部署后”脚本具有如下部分:

-- 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

Is there a better or more conventional way to structure such static data scripts as part of an SSDT project? 是否有更好或更常规的方法来将这种静态数据脚本构造为SSDT项目的一部分?

To track whether or not the field has already been initialized, try adding an Extended Property when the initialize is performed (it can also be used to determine the need for the initialize): 若要跟踪该字段是否已经初始化,请在执行初始化时尝试添加扩展属性(也可以用来确定是否需要初始化):

To add the extended property: 要添加扩展属性:

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;

To check for the extended property: 要检查扩展属性:

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

For reference data, try using a MERGE. 有关参考数据,请尝试使用MERGE。 It's MUCH cleaner than the triple-set of queries you're using. 它比您正在使用的三组查询要干净得多。

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; 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM