小编典典

两张表之间的日期差

sql

我有两个带有开始和结束字段的表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 Server(2012及更高版本),并且我的字段类型为DateTime2。

我的主要问题是图纸中的第一种情况=>当两个或两个以上的间隔被一个覆盖时。
非常感谢您的宝贵时间。


阅读 167

收藏
2021-04-15

共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在最终选择中我将不止一次使用它(如果您愿意,您可以无需创建视图,只需将查询用作子查询即可)

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

我还需要另一种观点认为对UNION ALLstartsends来自T1T2这样

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并且2015-05-16 14:00:00 NULL因为我的查询周期的调整的最后一个。

这是有关SQLFiddle的有效解决方案:http
://sqlfiddle.com/#!9/6a8a9/1

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

2021-04-15