两个表之间的日期差异

Date difference between two tables


我有两个带有开始和结束字段的表 T1 和 T2。
我想要的是:T2 中不在 T1 中的部分。

绘图

T1 :   [----][----]          [-----]
T2 : [---------------]    [------------]
R  : [-]          [--]    [--]     [---]

R这里是结果

数据

T1 : 2015-05-14 07:00:00 2015-05-14 14:00:00 2015-05-14 14:00:00 2015-05-14 19:00:00 2015-05-16 12:30:00 2015-05-16 13:30:00

T2 : 2015-05-14 05:00:00 2015-05-14 23:00:00 2015-05-16 12:00:00 2015-05-16 14:00:00

R : 2015-05-14 05:00:00 2015-05-14 07:00:00 2015-05-14 19:00:00 2015-05-14 23:00:00 2015-05-16 12:00:00 2015-05-16 12:30:00 2015-05-16 13:30:00 2015-05-16 14:00:00

我使用 SQL 服务器(2012 及以上),我的字段类型是 DateTime2。

我这里的主要问题是我绘图中的第一种情况 => 当你有 2 个或更多间隔被一个覆盖时。
非常感谢您的宝贵时间。

我得出的答案:

    --data init
DECLARE @t1 AS TABLE    (db DATETIME ,de DATETIME    );
DECLARE @t2 AS TABLE    (db DATETIME ,de DATETIME    );

INSERT  INTO @t1  ( db ,    de  )VALUES  ( '2015-05-14 07:00:00.000' ,    '2015-05-14 14:00:00.000'  );
INSERT  INTO @t1  ( db ,    de  )VALUES  ( '2015-05-14 14:00:00' ,    '2015-05-14 19:00:00'  );
INSERT  INTO @t1  ( db ,    de  )VALUES  ( '2015-05-16 12:30:00' ,    '2015-05-16 13:30:00'  );

INSERT  INTO @t2  ( db ,    de  )VALUES  ( '2015-05-14 05:00:00' ,    '2015-05-14 23:00:00'  );
INSERT  INTO @t2  ( db ,    de  )VALUES  ( '2015-05-16 12:00:00' , '2015-05-16 14:00:00'  )

--actual answer 
;WITH    cte
    AS ( SELECT   * ,
ROW_NUMBER() OVER ( PARTITION BY db ORDER BY de ) num ,
ROW_NUMBER() OVER ( PARTITION BY de ORDER BY db DESC ) num2
   FROM     ( SELECT    t2.db ,
t.db AS de
  FROM @t2 t2
JOIN @t1 t ON t.db BETWEEN t2.db AND t2.de
  AND t.de BETWEEN t2.db AND t2.de
  UNION
  SELECT    t.de AS db ,
t2.de
  FROM @t2 t2
JOIN @t1 t ON t.db BETWEEN t2.db AND t2.de
  AND t.de BETWEEN t2.db AND t2.de
) zzz
 )
    SELECT  *
    FROM    cte
    WHERE   num = 1
AND num2 = 1;

所以对于那些只看图不明白问题的人,我将在这里添加一张图,其中包含 OP 的问题以及所提供的数据。

这种问题只有处理过才会明白

           dt2  dt3|dt4  dt5                   dt8       dt9
T1 :        [-----]|[-----]                     [---------]
      dt1                        dt6  dt7                        dt10
T2 :   [--------------------------]    [--------------------------]
      R1s  R1e           R2s     R2e  R3s      R3e       R4s     R4e
R  :   [----]             [-------]    [--------]         [-------]

标签表示:

dt1 - Date 1
dt2 - Date 2
....
dt10 - Date 10
-------
R1s - Result date start 1
R1e - Result date end 1
R2s - Result date start 2
R2e - Result date end 2
...

它们是日期和时间段。请注意,日期 3 和日期 4 之间的 | 只是为了表明两者之间没有间隔。

我的解决方案

对于此类问题,您要做的第一件事就是了解您的所有月经开始结束是一个整体所以我用它创建了一个 VIEW,因为我将在最终的 select 中多次使用它(如果你愿意,你不需要创建视图,只需将查询用作子查询)

create or replace view vw_times as
    select dtstart as dtperiod from t1 UNION
    select dtend from t1 UNION
    select dtstart from t2 UNION
    select dtend from t2;

此视图将在一个字段中提供所有日期(开始和结束)dtperiod

我还需要从 T1T2 中 UNION 所有 startsends 的另一种观点,所以

create or replace view vw_times2 as
    select dtstart, dtend from t1 UNION
    select dtstart, dtend from t2;

所以最终查询将是:

SELECT t.dtstart, t.dtend
  FROM (
        SELECT t1.dtperiod as dtstart,
               (SELECT min(dtperiod) second 
                  FROM vw_times x where x.dtperiod > t1.dtperiod) as dtend
          FROM vw_times t1
                   LEFT JOIN (SELECT (dtperiod - interval 1 second) dtperiod 
                                FROM vw_times) t2 
                          ON (t1.dtperiod = t2.dtperiod)
         WHERE t2.dtperiod is null
       ) t LEFT JOIN vw_times2 t2 ON (    t.dtstart = t2.dtstart
                                      AND t.dtend = t2.dtend)
 WHERE t2.dtstart IS NULL
   AND DAY(t.dtstart) = DAY(t.dtend)
 ORDER BY t.dtstart;

请记住,我使用的是我在此查询中创建的视图,因此可读性更强。

在此查询中有一件值得一提的事情。由于您只需要每天缺失的经期,因此我添加了此过滤器 AND DAY(t.dtstart) = DAY(t.dtend),因此查询不会为您提供几天之间缺失的经期。在你的样本集中,它将是 2015-05-14 23:00:00 2015-05-16 12:00:002015-05-16 14:00:00 NULL 最后一个,因为我的查询的周期调整。

这是 SQLFiddle 上的工作解决方案:http://sqlfiddle.com/#!9/6a8a9/1

请注意,我使用 MySql 创建了它 (sqlfiddle)(因为它在 sql 服务器上不稳定)。因为它只使用普通 sql 它在 SQLServer 上的工作方式相同(唯一的区别是日期提取。在答案中我添加了 sql 服务器版本)。