Sql 具有时间间隔的表行实例的快照

Sql 具有时间间隔的表行实例的快照,sql,analytics,teradata,data-warehouse,window-functions,Sql,Analytics,Teradata,Data Warehouse,Window Functions,我不知道该怎么称呼这种现象。我刚刚将其命名为“具有时间间隔的表行实例快照”。我们需要创建一个新的实体,它是两个表的连接,但是这两个表有历史记录,我们需要合并到这个实体中。请看下面的示例: 在图中,您可以看到我们有两个表ABC和PQR,ID为键列。我们需要创建一个表ABCPQR,它将连接这两个表,并且这两个表的历史记录将包含来自各自表的两个属性的合并历史记录 如何在数据库中实现这一点?我正在使用Teradata作为数据库,有什么算法可以实现这一点吗?没有复杂的算法。带交叉连接、介于和最大/最小函

我不知道该怎么称呼这种现象。我刚刚将其命名为“具有时间间隔的表行实例快照”。我们需要创建一个新的实体,它是两个表的连接,但是这两个表有历史记录,我们需要合并到这个实体中。请看下面的示例:

在图中,您可以看到我们有两个表ABC和PQR,ID为键列。我们需要创建一个表ABCPQR,它将连接这两个表,并且这两个表的历史记录将包含来自各自表的两个属性的合并历史记录


如何在数据库中实现这一点?我正在使用Teradata作为数据库,有什么算法可以实现这一点吗?

没有复杂的算法。带交叉连接、介于和最大/最小函数的简单sql即可

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数据类型快速完成此操作。句点是日期或时间戳的范围。它使用两个日期或时间戳作为参数,第一个用于开始日期,第二个用于结束日期(直到但不包括)

在您的情况下,我们将把您的
开始日期
结束日期
转换为执行联接的时段。我们将使用特定于时段的函数
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;
我们在这里获得了一些奖金:

  • 逻辑清晰而简单。没有用嵌套的CASE语句测试max(开始日期)和min(结束日期)以及所有那些可怕的东西
  • 如果您必须加入第三个表,只需将其开始和结束日期转换为validperiod,并使用
    t1.validperiod P_INTERSECT t2.validperiod P_INTERSECT t3.validperiod不为NULL
    Simple
  • 还有一些其他非常有用的函数是基于周期的,它们可以让这样的工作变得简单。例如,NORMALIZE将基于复合键、重叠和会议期间将多个记录合并在一起

  • 最后,作为一项规则,当我创建表并且该表有开始日期和结束日期时,我总是创建一个名为validperiod的新字段,并像在这些子查询中一样加载它。然后,您不必转换为句点,您的加入就会变得友好。只需抓取已存储的validperiod列并开始P_相交。它消除了其他丑陋连接和选择的所有工作。

    感谢您的回答Bhavesh。嗨,JNevill。谢谢你的回答,但我想问一个简短的问题。你知道当我们连接多个表时P_INTERSECT是如何执行的吗?它非常快。我有一个p_与6或7个表相交,每个表有上万条记录,它在一分钟左右返回。这也是所有的左连接,所以我合并了每一个可能的交叉点。我意识到我在评论中说我是在结束(句点)-1,但忘了在SQL中实现它。我已将该字段的答案更新为:
    previor(End(t1.validperiod P_INTERSECT t2.validperiod))
    。此外,您可能会发现这篇关于Teradata的Period功能的老博文值得一看:这是一个很好的资源,有很多例子和解释。此外,我刚刚运行了我在第二条评论中提到的大型P_INTERSECT sql。它需要6个表,每个表有200k到600k条记录,它在单节点盒上2-3秒内将663746条记录输出到一个新表。