5 sql-server temporal-tables sql-server-2016
我们希望在 SQL Server 2016 中实现时态表。我们正在创建一个数据仓库并开发类型 2 缓慢变化的维度表。
对于 BeginDate,我们希望它取决于交易日期而不是当前的 getdate 时间。我们正在重新处理交易历史记录。下面的示例中,客户具有健身房或银行状态,并且根据交易日期从不活动状态变为活动状态或待处理状态。
我们目前有这个。
CREATE TABLE dbo.Department
(
CustomerId int primary key,
MembershipStatus int,
TransactionDate datetime
);
Run Code Online (Sandbox Code Playgroud)
我们想创建一个这样的表。
CREATE TABLE dbo.DepartmentHistory
(
CustomerId int primary key,
MembershipStatus int,
TransactionDate datetime,
BeginDatetime datetime,
EndDatettime datetime
);
Run Code Online (Sandbox Code Playgroud)
示例用法如下:
+------------+--------+------------+---------+ | 客户 ID | 状态 | 开始日期 | 结束日期 | +------------+--------+------------+---------+ | 1 | 普 | 2018 年 3 月 5 日 | 空| +------------+--------+------------+---------+
+------------+--------+------------+------------+ | 客户 ID | 状态 | 开始日期 | 结束日期 | +------------+--------+------------+------------+ | 1 | 普 | 2018 年 3 月 5 日 | 2018 年 4 月 21 日 | | 1 | 一个 | 2018 年 4 月 21 日 | 空| +------------+--------+------------+------------+
临时表是系统版本1 ,因此“手动设置”给定历史行的时间戳的唯一方法是更改该行被修改时的操作系统时间,而您可能不想这样做。
如果您想在历史表上“手动设置”时间范围以使其支持时态查询语法,您可以通过在现有数据之上手动应用时态表来实现。这有点棘手,需要底层数据符合时间历史版本控制规则。当时态表被引入时,Google 上就充斥着关于此问题的各种博客文章;因为我已经有一段时间没有使用这个确切的用例了,所以现在我将任意链接到这个看起来很有希望的示例。
请记住,系统版本控制的时态表实际上是两个表- 一个“现在”表和一个“历史”表压缩在一起......
create table dbo.b_now (
i int not null primary key
,info varchar(10)
,start_dt datetime2 generated always as row start
,end_dt datetime2 generated always as row end
,period for system_time (start_dt, end_dt)
) with (system_versioning = on (history_table = dbo.b_history));
go
insert b_now (i,info)
values
(1,'AAA')
,(2,'BBB');
go
update b_now set info = 'XXX' where i = 1
go
select * from b_history
select * from b_now
go
Run Code Online (Sandbox Code Playgroud)
请注意,虽然b_now
似乎是“基表”并支持时间语法 - 它只是一个单独的对象。删除对象之间的系统版本控制绑定强化了这一点。
牢记这一点 - 并记住我们可以来回切换SYSTEM_VERSIONING
,我们可以告诉 SQL Server 对任意一对对象任意应用(ON
并任意忽略)系统版本控制规则,只要OFF
......ON
但我想要示例代码!
是的,我想你可能会 - 所以试试这个......
drop table if exists a_now ,a_history;
go
create table a_now (
i int not null primary key
,info varchar(10)
,start_dt datetime2 not null
,end_dt datetime2 not null
-- you'll want this CHECK later...
check (end_dt = convert(datetime2,'9999-12-31 23:59:59.9999999'))
);
go
create table a_history (
i int not null
,info varchar(10)
,start_dt datetime2 not null
,end_dt datetime2 not null
);
go
declare @end_of_time datetime2 = '9999-12-31 23:59:59.9999999';
insert a_now values
(1,'XXX','2017-01-01',@end_of_time)
,(2,'BBB','2017-01-01',@end_of_time)
insert a_history values
(1,'AAA','2016-01-01','2017-01-01');
go
select * from a_now
select * from a_history
Run Code Online (Sandbox Code Playgroud)
...看起来很像b_now
并且b_history
,不是吗?太糟糕了,这不是一个合适的系统表......
alter table a_now
add period for system_time (start_dt, end_dt);
go
alter table a_now
set (system_versioning = on (history_table = dbo.a_history));
go
Run Code Online (Sandbox Code Playgroud)
等等呃……?您甚至可以在“现在”表的顶部放置一个视图,以隐藏您对命名约定的滥用。
create or alter view a
as
select * from a_now
go
select *
from a
for system_time as of '2016-06-01'
Run Code Online (Sandbox Code Playgroud)
好的,是的...但是我如何添加新的行呢,Smarty Pants 先生?
非常仔细……就是这样。
alter table a_now
set (system_versioning = off);
alter table a_now
drop period for system_time;
go
declare @end_of_time datetime2 = '9999-12-31 23:59:59.9999999';
insert a_now values
(3,'CCC','2018-01-01',@end_of_time);
update a_now set
start_dt = '2018-01-01'
,info = 'YYYY'
where i = 1;
insert a_history
values
(1,'XXX','2017-01-01','2018-01-01')
alter table a_now
add period for system_time (start_dt, end_dt);
go
alter table a_now
set (system_versioning = on (history_table = dbo.a_history));
go
select * from a for system_time as of '2017-06-01'
Run Code Online (Sandbox Code Playgroud)
我将其留给读者(您)将INSERT
//UPDATE
逻辑DELETE
和相关的DROP
/re-SET
系统版本控制包装到可重用的模块中。
1. 注意,创建时态表所需的 DDLperiod for SYSTEM_time
中的语法暗示了这一点
归档时间: |
|
查看次数: |
2931 次 |
最近记录: |