如何复制时态表

Posted

技术标签:

【中文标题】如何复制时态表【英文标题】:How do I replicate a temporal table 【发布时间】:2019-01-07 02:37:00 【问题描述】:

我有一个临时表,我想使用事务复制来复制它。历史表不能有事务复制所需的主键。当我尝试复制当前表时,复制失败,因为它无法插入到 GENERATED ALWAYS AS ROW STARTGENERATED ALWAYS AS ROW END 列中。

【问题讨论】:

【参考方案1】:

Microsoft Documentation 状态:

快照和事务复制:仅支持未启用临时的单个发布者和启用临时的订阅者。

这是一个包含一些虚拟数据的示例时态表:

CREATE TABLE [dbo].[TemporalTest]
(
    [EmployeeID] CHAR(6) NOT NULL,
    [EmployeeName] VARCHAR(50) NOT NULL,
    [EFF_STRT_TS] DATETIME2(7) GENERATED ALWAYS AS ROW START NOT NULL,
    [EFF_END_TS] DATETIME2(7) GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME ([EFF_STRT_TS],[EFF_END_TS]),
CONSTRAINT [PK_TemporalTest] PRIMARY KEY CLUSTERED ([EmployeeID] ASC),
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[TemporalTest_HIST]));
GO

INSERT INTO [dbo].[TemporalTest]
([EmployeeID],[EmployeeName])
VALUES
    ('000001','Jane Doe'),
    ('000002','John Smith'),
    ('000003','John Deer'),
    ('000004','Dear John')

DELETE FROM [dbo].[TemporalTest]
WHERE [EmployeeID] = '000003'

UPDATE [dbo].[TemporalTest]
SET [EmployeeName] = 'Jane Smith'
WHERE [EmployeeID] = '000001'

在复制之前,关闭SYSTEM_VERSIONING

ALTER TABLE [dbo].[TemporalTest]
SET (SYSTEM_VERSIONING = OFF);

设置事务复制,并排除周期列 [EFF_STRT_TS][EFF_END_TS]。 在复制端,添加周期列。

ALTER TABLE [dbo].[TemporalTest]
ADD [EFF_STRT_TS] DATETIME2(7) NULL,
    [EFF_END_TS] DATETIME2(7) NULL

使用 SSIS,将历史表 [TemporalTest_HIST] 从发布者复制到订阅者。同样使用 SSIS,将当前的 [TemporalTest] 表从发布者覆盖到订阅者,以便时间段列值完全匹配并且不为空。之后,修改订阅方的列,将周期列设为NOT NULL,并将它们设置为PERIOD FOR SYSTEM_TIME

ALTER TABLE [dbo].[TemporalTest]
ALTER COLUMN [EFF_STRT_TS] DATETIME2(7) NOT NULL

ALTER TABLE [dbo].[TemporalTest]
ALTER COLUMN [EFF_END_TS] DATETIME2(7) NOT NULL

ALTER TABLE [dbo].[TemporalTest]
ADD PERIOD FOR SYSTEM_TIME ([EFF_STRT_TS],[EFF_END_TS])

在发布者和订阅者端,设置SYSTEM_VERSIONING = ON

ALTER TABLE [dbo].[TemporalTest]
SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[TemporalTest_HIST]));

从现在开始,发布者和订阅者将各自维护自己的系统版本化时态表。整个时态表结构没有被复制,因此周期列可能不会完全对齐,具体取决于复制需要多长时间。

【讨论】:

【参考方案2】:

在我的情况下,关闭 SYSTEM_VERSIONING 是不够的。 我还不得不删除 perdiod 列:

ALTER TABLE TemporalTest DROP PERIOD FOR SYSTEM_TIME

仅在发布属性中排除它们,在订阅者初始化期间完成以下错误

消息 13504,第 16 级,状态 1,第 36 行 缺少临时“始终作为行开始”列定义。

初始化后需要添加周期列并开启系统版本控制

ALTER TABLE [dbo].[TemporalTest]
ADD PERIOD FOR SYSTEM_TIME ([EFF_STRT_TS],[EFF_END_TS])

ALTER TABLE [dbo].[TemporalTest]
SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[TemporalTest_HIST]));

【讨论】:

【参考方案3】:

我们只需要复制当前表(与 Microsoft 假设的情况相反)。我们在“当前”表上创建了一个非临时索引视图,并复制了索引视图。我们跳过了视图中的系统版本列(我认为这并不重要)。

【讨论】:

以上是关于如何复制时态表的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 JPA 实现时态表?

如何将时态表添加到 EF Code-First DBContext?

如何将系统版本化的时态表与实体框架一起使用?

如何在Oracle中复制表结构和表数据

删除系统版本化时态表的过程

在 EF6 中使用时态表 - PostgreSQL