Date difference between two tables

久未见 提交于 2019-12-02 18:17:02

问题



I have two tables T1 and T2 with start and end fields.
What I want is : the parts of T2 that are not in T1.

The Drawing

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

R here is the result.

Data

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

I use SQL Server (2012 and more) and the type of my fields are DateTime2.

My main issue here is the first case in my drawing => When you have 2 or more intervals covered by one.
Thanks a lot for your time.


回答1:


So for the guys that didn't understand the problem only by the drawing I will add a drawing here with the OP's problem with the data provided.

This is a kind of problem that you only understand if you already dealt with.

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

The labels means:

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

They are periods of date and time. Note that the | between Date 3 and 4 is just to show that there is no interval between then.

My Solution

For this type of problem, the very first thing you have to do is to know all your periods starts and ends as one so I created a VIEW with it as I will use it more than once on the final select (if you wish, you don't need to create the view just use the query as subquery)

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;

This view will give me all dates (starts and ends) in just one field dtperiod

I will also need another view to to UNION all starts and ends from both T1 and T2 so

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

So the final query will be:

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;

Remember that I'm using the views I created on this query so it can be more readable.

There's on thing worth to mention on this query. Since you only want as result the missing periods for each day, I've added this filter AND DAY(t.dtstart) = DAY(t.dtend) so the query won't give you missing periods between days. In your sample set it would be 2015-05-14 23:00:00 2015-05-16 12:00:00 and 2015-05-16 14:00:00 NULL last one because of the period tweak on my query.

Here is the working solution on SQLFiddle: http://sqlfiddle.com/#!9/6a8a9/1

Note that I created it (sqlfiddle) using MySql (because it is unstable with sqlserver). Since it only use plain sql it will work as the same on SQLServer (the only difference is day extraction. Here on the answer I added the sqlserver version).




回答2:


Answer I came out with:

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


来源:https://stackoverflow.com/questions/34138553/date-difference-between-two-tables

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!