查找时间与两个不同的时间轴重叠

时间:2015-01-06 23:37:04

标签: sql sql-server tsql

我正在使用SQL SERVER。我有两个表table1和table2。它们都存储时间间隔,为简单起见,两者都有两个datetime2列,列名为表1的S1和S2,表2的T1和T2,每行S1大于S2,完全为表2。我想计算S2和S1之间的间隔值(如时间轴),并在T1和S2上减去T1和T2的重叠。我试过这个,但不能超过计算的第一部分

DECLARE @x float
SET x=0
SELECT SUM(S1-S2)-x from table1
 (set x =(SELECT (T1-T2) FROM table2
 WHERE T1>=S1 and T2<=S2));

示例:

S2= 10/25/2012 ; S1= 11/30/2012;


assume that we have three rows in table 2

T2=10/20/2012 , T1=10/28/2012

T2=11/4/2012  , T1=11/8/2012

T2=11/22/2012 , T1=11/30/2012

我想要的是找到S1和S2之间的总分钟数,除了与第二个表T1和T2间隔重叠的分钟数。当T1和T2之间的整个间隔在S1和S2的间隔中时,我的查询适用于第二个表中的第二行。  这个例子有点复杂希望这个例子有帮助

查询工作正常,但当T1或T2中的一个处于S1和S2间隔时,我无法使用查询计算重叠值。我应该运行多个查询吗?这里有什么相似之处?

1 个答案:

答案 0 :(得分:2)

我在这个例子中使用SQL Server 2008。 此解决方案假设表T中的所有间隔彼此不重叠。

以下文章详细解释了区间代数,我认为它们是一本非常好的读物。他们也有很好的图表。

Comparing date ranges

http://salman-w.blogspot.com.au/2012/06/sql-query-overlapping-date-ranges.html

http://www.ics.uci.edu/~alspaugh/cls/shr/allen.html

http://stewashton.wordpress.com/2014/03/11/sql-for-date-ranges-gaps-and-overlaps/

创建包含样本数据的表

我以比原始问题更难以混淆的方式命名列。我添加了一些不重叠的额外间隔,以说明建议的解决方案将其过滤掉。

DECLARE @TableS TABLE (ID int IDENTITY(1,1), DateFromS date, DateToS date);
DECLARE @TableT TABLE (ID int IDENTITY(1,1), DateFromT date, DateToT date);

INSERT INTO @TableS (DateFromS, DateToS) VALUES ('2012-10-25', '2012-11-30');
INSERT INTO @TableS (DateFromS, DateToS) VALUES ('2015-10-25', '2015-11-30');

INSERT INTO @TableT (DateFromT, DateToT) VALUES ('2012-10-20', '2012-10-28');
INSERT INTO @TableT (DateFromT, DateToT) VALUES ('2012-11-04', '2012-11-08');
INSERT INTO @TableT (DateFromT, DateToT) VALUES ('2012-11-22', '2012-11-30');
INSERT INTO @TableT (DateFromT, DateToT) VALUES ('2010-11-22', '2010-11-30');
INSERT INTO @TableT (DateFromT, DateToT) VALUES ('2020-11-22', '2020-11-30');

查找重叠间隔

我假设我们想要对表S中的每一行以及表T中的每一行进行这些计算。如果不是这种情况,则应该使用一些额外条件来连接表。

在这个例子中,我只使用天精度,而不是分钟,我假设开始和结束日期是包含的,即2000年1月1日和01/01/2000之间的持续时间是一天。将此扩展到精确的精度应该相当简单。

SELECT *
    ,ISNULL(1+DATEDIFF(day, MaxDateFrom.DateFrom, MinDateTo.DateTo), 0) AS OverlappedDays
FROM
    @TableS AS TS
    LEFT JOIN @TableT AS TT ON TS.DateFromS <= TT.DateToT AND TS.DateToS >= TT.DateFromT
    -- all periods in TS, which overlap with periods in TT
    --(StartA <= EndB)  and  (EndA >= StartB)
    CROSS APPLY
    (
        SELECT CASE WHEN TS.DateFromS > TT.DateFromT THEN TS.DateFromS ELSE TT.DateFromT END AS DateFrom
    ) AS MaxDateFrom
    CROSS APPLY
    (
        SELECT CASE WHEN TS.DateToS < TT.DateToT THEN TS.DateToS ELSE TT.DateToT END AS DateTo
    ) AS MinDateTo

LEFT JOIN中的条件仅留下重叠的间隔。要计算重叠间隔的持续时间,我使用两个CROSS APPLYs。这是此中间查询的结果集:

ID   DateFromS    DateToS      ID   DateFromT    DateToT      DateFrom     DateTo       OverlappedDays
1    2012-10-25   2012-11-30   1    2012-10-20   2012-10-28   2012-10-25   2012-10-28   4
1    2012-10-25   2012-11-30   2    2012-11-04   2012-11-08   2012-11-04   2012-11-08   5
1    2012-10-25   2012-11-30   3    2012-11-22   2012-11-30   2012-11-22   2012-11-30   9
2    2015-10-25   2015-11-30   NULL NULL         NULL         NULL         NULL         0

注意,最后一行对应于表S中的间隔与表T中的任何间隔不重叠的情况。

计算持续时间

现在我们只需要总结表S中每个原始行的重叠间隔T的持续时间,并从间隔S的持续时间中减去它。

SELECT
    TS.ID
    ,TS.DateFromS
    ,TS.DateToS
    ,1+DATEDIFF(day, TS.DateFromS, TS.DateToS) AS DurationS
    ,ISNULL(SUM(1+DATEDIFF(day, MaxDateFrom.DateFrom, MinDateTo.DateTo)), 0) AS DurationOverlapped
    ,1+DATEDIFF(day, TS.DateFromS, TS.DateToS)
    - ISNULL(SUM(1+DATEDIFF(day, MaxDateFrom.DateFrom, MinDateTo.DateTo)), 0) AS FinalDuration
FROM
    @TableS AS TS
    LEFT JOIN @TableT AS TT ON TS.DateFromS <= TT.DateToT AND TS.DateToS >= TT.DateFromT
    CROSS APPLY
    (
        SELECT CASE WHEN TS.DateFromS > TT.DateFromT THEN TS.DateFromS ELSE TT.DateFromT END AS DateFrom
    ) AS MaxDateFrom
    CROSS APPLY
    (
        SELECT CASE WHEN TS.DateToS < TT.DateToT THEN TS.DateToS ELSE TT.DateToT END AS DateTo
    ) AS MinDateTo
GROUP BY TS.ID, TS.DateFromS, TS.DateToS

这是结果集:

ID   DateFromS    DateToS      DurationS   DurationOverlapped   FinalDuration
1    2012-10-25   2012-11-30   37          18                   19
2    2015-10-25   2015-11-30   37          0                    37

您对FinalDuration值感兴趣,对于您的示例,该值为19,对于此示例,我为第二个间隔添加了37。 您可以向示例数据添加更多间隔以使用查询并查看它们的工作方式。

此解决方案假设表T中的所有间隔彼此不重叠。