Так что для ребят, которые не понимают проблемы только чертежом я добавить рисунок здесь с проблемой Ора с данными.
Это своего рода проблема, о которой вы только понимаете, если уже имеете дело.
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).
рисунки не помогут вашему делу. публиковать фактические данные –
Укажите свою СУБД (SQL * flavor *), так как функции даты/времени отличаются между реализациями. –
@vkp На самом деле это происходит, когда оно связано с датами. Нет необходимости в дополнительной информации. –