Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/78.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 寻找两条不同时间线的时间重叠_Sql_Sql Server_Tsql - Fatal编程技术网

Sql 寻找两条不同时间线的时间重叠

Sql 寻找两条不同时间线的时间重叠,sql,sql-server,tsql,Sql,Sql Server,Tsql,我正在使用SQL SERVER。我有两张桌子。表一和表二。它们都存储时间间隔,为了简单起见,只需说它们都有两个datetime2列,表1的列名是S1和S2,表2的列名是T1和T2,每一行S1都大于S2,正好是表2。我想计算S2和S1之间的间隔值(就像一个时间线),然后从S1和S2上T1和T2的重叠中减去它。我试过了,但不能超过计算的第一部分 DECLARE @x float SET x=0 SELECT SUM(S1-S2)-x from table1 (set x =(SELECT (T1-

我正在使用SQL SERVER。我有两张桌子。表一和表二。它们都存储时间间隔,为了简单起见,只需说它们都有两个datetime2列,表1的列名是S1和S2,表2的列名是T1和T2,每一行S1都大于S2,正好是表2。我想计算S2和S1之间的间隔值(就像一个时间线),然后从S1和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));
我想要的是找出S1和S2之间的总分钟数,除了与第二个表T1和T2间隔重叠的分钟数。当T1和T2之间的整个间隔在S1和S2之间时,我的查询用于第二个表中的第二行。 这有点复杂,希望这个例子能有所帮助


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

本例使用的是SQL Server 2008。 此解决方案假设表T中的所有间隔不相互重叠。

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

使用示例数据创建表 我用一种比原始问题更容易混淆的方式来命名这些专栏。我添加了几个不重叠的额外间隔,以说明建议的解决方案将它们过滤掉

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日到2000年1月1日之间的持续时间为一天。将其扩展到分钟精度应该相当简单

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
注意,最后一行对应于表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
您对
FinalDuration
值感兴趣,对于您的示例,该值为19,对于我为本示例添加的第二个时间间隔,该值为37。 您可以向示例数据中添加更多的时间间隔来处理查询,并查看它们是如何工作的


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

能否添加一个示例?阅读你的问题时我感到困惑。你希望从上面的例子中得到什么?
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
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