具有时间间隔的 table 行实例的快照
Snapshot of table row instance with time intervals
我不知道该怎么称呼这种现象。我刚刚将其命名为 "Snapshot of table row instance with time intervals"。我们有一种情况,我们需要创建一个新实体,它是两个 table 的 JOIN,但这两个 table 有历史,我们需要将历史合并到这个实体中。请看下面的例子:
在图像中,您可以看到我们有两个 tables ABC 和 PQR,其中 ID 作为键列。我们需要创建一个 table ABCPQR,它将加入这两个 table 并且它们的历史 table 将包含来自它们各自 table 的两个属性的合并历史。
如何在数据库中实现这个?我正在使用 Teradata 作为数据库,是否有任何算法可以实现这一点?
没有复杂的算法。简单的 sql 和 cross-join , between 和 greatest/least 函数就可以了。
create table abc
( id integer,
attr1 varchar(3),
start_date date,
end_date date)
PRIMARY INDEX(ID);
create table PQR
( id integer,
attr2 varchar(3),
start_date date,
end_date date)
PRIMARY INDEX(ID);
INSERT INTO abc VALUES(1,'LMN','2017-01-01','2017-02-28');
INSERT INTO abc VALUES(1,'HGI','2017-02-28','2017-03-15');
INSERT INTO abc VALUES(1,'STI','2017-03-15','2099-12-31');
INSERT INTO PQR VALUES(1,'KLM','2017-01-01','2017-01-20');
INSERT INTO PQR VALUES(1,'TLF','2017-01-20','2017-04-04');
INSERT INTO PQR VALUES(1,'SNQ','2017-04-04','2099-12-31');
select a.id,a.attr1,p.attr2,
cast(greatest(cast(a.start_date as int),cast(p.start_date as int)) as date)start_date,
cast(least(cast(a.end_date as int),cast(p.end_date as int)) as date)end_date
from abc a
inner join pqr p
on a.id=p.id
where a.start_date between p.start_date and p.end_date
or a.end_date between p.start_date and p.end_date
order by 4;
输出:
id attr1 attr2 start_date end_date
1 1 LMN KLM 1/1/2017 1/20/2017
2 1 LMN TLF 1/20/2017 2/28/2017
3 1 HGI TLF 2/28/2017 3/15/2017
4 1 STI TLF 3/15/2017 4/4/2017
5 1 STI SNQ 4/4/2017 12/31/2099
唯一不同的是我用了 2099 而不是 1999 来让事情变得简单。您也可以使用 1999 并自定义此查询(虽然不是首选)。
您可以使用 Teradata 的 PERIOD 数据类型快速完成这项工作。期间是日期或时间戳的范围。它需要两个日期或时间戳作为参数,第一个为开始日期,第二个为结束日期(直到但不包括)。
在您的情况下,我们会将您的 Start_Date
和 End_Date
转换为句点以执行连接。我们将使用周期特定函数 P_INTERSECT
来查找我们将加入的重叠周期。
SELECT
attr1,
attr2,
/*pull the BEGIN of the intersected period*/
BEGIN(t1.validperiod P_INTERSECT t2.validperiod) as startdate,
/*pull the END of the intersected period (subtracting a day since period end
dates are "up to but not including")*/
PRIOR(END(t1.validperiod P_INTERSECT t2.validperiod)) as enddate
FROM
(SELECT abc.*, PERIOD(start_date, NEXT(end_date)) as validperiod FROM abc) t1
INNER JOIN (SELECT pqr.*, PERIOD(start_Date, NEXT(end_date)) as validperiod FROM pqr) t2 ON
t1.id = t2.id
/*
* Now P_INTERSECT our two periods and look for Non-Null intersections
* The intersection is the date range where the two periods overlap
*/
AND t1.validperiod P_INTERSECT t2.validperiod IS NOT NULL;
我们在这里获得了一些奖励:
- 逻辑简洁明了。没有测试 max(start_date) 和 min(end_date) 嵌套的 CASE 语句和所有可怕的东西
- 如果您必须加入第三个 table,只需将其开始日期和结束日期转换为有效期并加入
t1.validperiod P_INTERSECT t2.validperiod P_INTERSECT t3.validperiod IS NOT NULL
简单简单。
- 还有一些其他真正有用的函数是基于句点的,可以让这样的工作变得轻而易举。例如,NORMALIZE 将根据复合键以及重叠和会议期间将多个记录合并在一起。
最后,通常,当我创建 table 并且 table 具有开始日期和结束日期时,我总是创建一个名为 validperiod 的新字段并像我们在那些子查询。然后,您不必转换为句点即可让您的连接变得友好。只需获取您已经存储的 validperiod 列并开始 P_INTERSECTing。它消除了其他丑陋的连接和选择的所有工作。
我不知道该怎么称呼这种现象。我刚刚将其命名为 "Snapshot of table row instance with time intervals"。我们有一种情况,我们需要创建一个新实体,它是两个 table 的 JOIN,但这两个 table 有历史,我们需要将历史合并到这个实体中。请看下面的例子:
在图像中,您可以看到我们有两个 tables ABC 和 PQR,其中 ID 作为键列。我们需要创建一个 table ABCPQR,它将加入这两个 table 并且它们的历史 table 将包含来自它们各自 table 的两个属性的合并历史。
如何在数据库中实现这个?我正在使用 Teradata 作为数据库,是否有任何算法可以实现这一点?
没有复杂的算法。简单的 sql 和 cross-join , between 和 greatest/least 函数就可以了。
create table abc
( id integer,
attr1 varchar(3),
start_date date,
end_date date)
PRIMARY INDEX(ID);
create table PQR
( id integer,
attr2 varchar(3),
start_date date,
end_date date)
PRIMARY INDEX(ID);
INSERT INTO abc VALUES(1,'LMN','2017-01-01','2017-02-28');
INSERT INTO abc VALUES(1,'HGI','2017-02-28','2017-03-15');
INSERT INTO abc VALUES(1,'STI','2017-03-15','2099-12-31');
INSERT INTO PQR VALUES(1,'KLM','2017-01-01','2017-01-20');
INSERT INTO PQR VALUES(1,'TLF','2017-01-20','2017-04-04');
INSERT INTO PQR VALUES(1,'SNQ','2017-04-04','2099-12-31');
select a.id,a.attr1,p.attr2,
cast(greatest(cast(a.start_date as int),cast(p.start_date as int)) as date)start_date,
cast(least(cast(a.end_date as int),cast(p.end_date as int)) as date)end_date
from abc a
inner join pqr p
on a.id=p.id
where a.start_date between p.start_date and p.end_date
or a.end_date between p.start_date and p.end_date
order by 4;
输出:
id attr1 attr2 start_date end_date
1 1 LMN KLM 1/1/2017 1/20/2017
2 1 LMN TLF 1/20/2017 2/28/2017
3 1 HGI TLF 2/28/2017 3/15/2017
4 1 STI TLF 3/15/2017 4/4/2017
5 1 STI SNQ 4/4/2017 12/31/2099
唯一不同的是我用了 2099 而不是 1999 来让事情变得简单。您也可以使用 1999 并自定义此查询(虽然不是首选)。
您可以使用 Teradata 的 PERIOD 数据类型快速完成这项工作。期间是日期或时间戳的范围。它需要两个日期或时间戳作为参数,第一个为开始日期,第二个为结束日期(直到但不包括)。
在您的情况下,我们会将您的 Start_Date
和 End_Date
转换为句点以执行连接。我们将使用周期特定函数 P_INTERSECT
来查找我们将加入的重叠周期。
SELECT
attr1,
attr2,
/*pull the BEGIN of the intersected period*/
BEGIN(t1.validperiod P_INTERSECT t2.validperiod) as startdate,
/*pull the END of the intersected period (subtracting a day since period end
dates are "up to but not including")*/
PRIOR(END(t1.validperiod P_INTERSECT t2.validperiod)) as enddate
FROM
(SELECT abc.*, PERIOD(start_date, NEXT(end_date)) as validperiod FROM abc) t1
INNER JOIN (SELECT pqr.*, PERIOD(start_Date, NEXT(end_date)) as validperiod FROM pqr) t2 ON
t1.id = t2.id
/*
* Now P_INTERSECT our two periods and look for Non-Null intersections
* The intersection is the date range where the two periods overlap
*/
AND t1.validperiod P_INTERSECT t2.validperiod IS NOT NULL;
我们在这里获得了一些奖励:
- 逻辑简洁明了。没有测试 max(start_date) 和 min(end_date) 嵌套的 CASE 语句和所有可怕的东西
- 如果您必须加入第三个 table,只需将其开始日期和结束日期转换为有效期并加入
t1.validperiod P_INTERSECT t2.validperiod P_INTERSECT t3.validperiod IS NOT NULL
简单简单。 - 还有一些其他真正有用的函数是基于句点的,可以让这样的工作变得轻而易举。例如,NORMALIZE 将根据复合键以及重叠和会议期间将多个记录合并在一起。
最后,通常,当我创建 table 并且 table 具有开始日期和结束日期时,我总是创建一个名为 validperiod 的新字段并像我们在那些子查询。然后,您不必转换为句点即可让您的连接变得友好。只需获取您已经存储的 validperiod 列并开始 P_INTERSECTing。它消除了其他丑陋的连接和选择的所有工作。