2015-12-07 2 views
0


У меня есть две таблицы 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.

Моя основная проблема здесь - первый случай в моем чертеже => Когда у вас есть 2 или более интервалов, покрытых одним.
Большое спасибо за ваше время.

+3

рисунки не помогут вашему делу. публиковать фактические данные –

+1

Укажите свою СУБД (SQL * flavor *), так как функции даты/времени отличаются между реализациями. –

+0

@vkp На самом деле это происходит, когда оно связано с датами. Нет необходимости в дополнительной информации. –

ответ

1

Так что для ребят, которые не понимают проблемы только чертежом я добавить рисунок здесь с проблемой Ора с данными.

Это своего рода проблема, о которой вы только понимаете, если уже имеете дело.

  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 всех 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 последнее из-за настройки периода по моему запросу.

Вот рабочий раствор на SQLFiddle: http://sqlfiddle.com/#!9/6a8a9/1

Обратите внимание, что я создал его (sqlfiddle), используя MySql (потому что она неустойчива с SQLServer). Поскольку он использует только простой sql, он будет работать одинаково на SQLServer (единственное отличие - извлечение дня. Здесь, в ответ, я добавил версию sqlserver).

+0

Это работает для меня, спасибо за ваши объяснения и время! – Minouz

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; 

 Смежные вопросы

  • Нет связанных вопросов^_^