【问题标题】:Date difference between two tables两个表之间的日期差异
【发布时间】:2015-12-08 02:40:26
【问题描述】:


我有两个表 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 个或更多间隔被一个覆盖时。
非常感谢您的宝贵时间。

【问题讨论】:

  • 图纸对您的事业没有帮助。发布实际数据
  • 指定您的 RDBMS(SQL 风格),因为日期/时间函数因实现而异。
  • 不适合我。我真的不确定要问什么。
  • 好吧,我是!并开始写答案!对于处理这种情况的人来说,这很常见。
  • @Siyual 我会尽快回答我关于日期是否包含在内的问题。

标签: sql sql-server date intervals


【解决方案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

我还需要另一个视图来联合所有 startsends 来自 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:002015-05-16 14:00:00 NULL,因为我对查询进行了周期调整。

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

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

【讨论】:

  • 这对我有用,感谢您的解释和时间!
【解决方案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;

【讨论】:

    猜你喜欢
    • 2011-10-29
    • 1970-01-01
    • 2014-02-12
    • 2015-09-14
    • 2015-06-21
    • 2020-02-06
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多