两个表之间的日期差异

时间:2015-12-07 16:35:09

标签: sql sql-server date intervals


我有两个表T1和T2,包含起始和结束字段。
我想要的是:T2中不属于T1的部分。

绘图

T1 :   [----][----]          [-----]
T2 : [---------------]    [------------]
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 Server(2012及更多),我的字段类型是DateTime2。

我的主要问题是我的绘图中的第一个案例=>当你有2个或更多间隔时,一个 非常感谢你的时间。

2 个答案:

答案 0 :(得分: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之间的|只是为了表明之间没有间隔。

我的解决方案

对于此类问题,您要做的第一件事就是将所有句点开始结束作为一个,因此我创建了{{1}因为我会在最终选择中多次使用它(如果你愿意,你不需要创建视图只需使用查询作为子查询)

VIEW

此视图只会在一个字段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;

中显示所有日期(开始和结束)

我还需要从dtperiodstarts向UNION所有endsT1提供另一个视图,以便

T2

所以最后的查询将是:

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:00最后一个。

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

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

答案 1 :(得分:0)

答案我出来了:

    --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;