两个表之间的日期差异
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
我还需要从 T1
和 T2
中 UNION 所有 starts
和 ends
的另一种观点,所以
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)(因为它在 sql 服务器上不稳定)。因为它只使用普通 sql 它在 SQLServer 上的工作方式相同(唯一的区别是日期提取。在答案中我添加了 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 服务器(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
我还需要从 T1
和 T2
中 UNION 所有 starts
和 ends
的另一种观点,所以
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)(因为它在 sql 服务器上不稳定)。因为它只使用普通 sql 它在 SQLServer 上的工作方式相同(唯一的区别是日期提取。在答案中我添加了 sql 服务器版本)。