我有两个带有开始和结束字段的表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。
我的主要问题是图纸中的第一种情况=>当两个或两个以上的间隔被一个覆盖时。 非常感谢您的宝贵时间。
因此,对于那些仅凭图纸无法理解问题的人,我将在此处添加带有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在最终选择中我将不止一次使用它(如果您愿意,您可以无需创建视图,只需将查询用作子查询即可)
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
dtperiod
我还需要另一种观点认为对UNION ALLstarts和ends来自T1与T2这样
starts
ends
T1
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并且2015-05-16 14:00:00 NULL因为我的查询周期的调整的最后一个。
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版本)。