我有两个表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个或更多间隔时,一个
非常感谢你的时间。
答案 0 :(得分: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之间的|
只是为了表明之间没有间隔。
我的解决方案
对于此类问题,您要做的第一件事就是将所有句点开始和结束作为一个,因此我创建了{{1}因为我会在最终选择中多次使用它(如果你愿意,你不需要创建视图只需使用查询作为子查询)
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
和starts
向UNION所有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
最后一个。
以下是SQLFiddle的工作解决方案:http://sqlfiddle.com/#!9/6a8a9/1
请注意,我使用MySql创建它(sqlfiddle)(因为它与sqlserver不稳定)。因为它只使用普通的sql,它在SQLServer上的工作方式是相同的(唯一的区别是日提取。这里的答案我添加了sqlserver版本。)
答案 1 :(得分:0)
答案我出来了:
--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;