Как разбить диапазон времени на две записи по заданному моменту времени?
Имеется таблица, в ней есть два поля: date_from и date_to.
Если диапазон времени проходит через определенную точку, например point, то запись с данным временем необходимо дублировать, а диапазон делить на два.
Например, если:
date_from = 23.04.2020 22:26:00
date_to = 23.04.2020 23:59:00
point = 23:00:00
, то у нас вместо одной записи появляется дубликат с новыми диапазонами времени:
1 from 23.04.2020 22:26:00 to 23.04.2020 23:00:00
2 from 23.04.2020 23:00:01 to 23.04.2020 23:59:00
Больше данных в файле Google Docs.
Не пониманию, как сделать проверку вхождения точки в данный интервал.
Но самое страшное, как проверить вхождение, если point = 00:00:00 (полночь)?
Проверка на SQL и PL/SQL.
Ответы (2 шт):
Попробуйте SQL запросом, вот так:
with params as (
select 'dd.mm.yyyy hh24:mi:ss' fmt, '00:00:00' point, 1/86400 sec from dual
),
testdata (date_from, date_to) as (
select to_date ('05.04.2020 18:53:23', fmt), to_date ('05.04.2020 19:27:23', fmt) from params union all
select to_date ('05.04.2020 22:50:09', fmt), to_date ('05.04.2020 23:20:09', fmt) from params union all
select to_date ('05.04.2020 23:30:29', fmt), to_date ('06.04.2020 00:00:29', fmt) from params union all
select to_date ('06.04.2020 01:40:33', fmt), to_date ('06.04.2020 02:15:33', fmt) from params
)
select
case level when 1 then date_from else point+1*sec end date_from,
case level when 1 then point else date_to end date_to
from (
select * from (
select
testdata.*, params.sec,
to_date (to_char (date_to,'dd.mm.yyyy')||point, fmt) point
from testdata cross join params
) where point between date_from and date_to
) connect by level <= 2;
Выведет поделенный на две запсиси диапазон, который проходит через полночь:
DATE_FROM DATE_TO
------------------- -------------------
2020-04-05 23:30:29 2020-04-06 00:00:00
2020-04-06 00:00:01 2020-04-06 00:00:29
Решение на PL/SQL выглядит более понятно:
create or replace type dateRange is object (dtFrom date, dtTo date)
/
create or replace type dateRanges is table of dateRange
/
create or replace function splitDateRangeByTimePoint (dr dateRange, tp char) return dateRanges is
fmt constant char(21) := 'dd.mm.yyyy hh24:mi:ss';
sec constant number := 1/86400;
point date := to_date (to_char (dr.dtTo,'dd.mm.yyyy')||tp, fmt);
ret dateRanges;
begin
return case
when point >= dr.dtFrom and point < dr.dtTo then
dateRanges (
dateRange (dr.dtFrom, point),
dateRange (point+1*sec, dr.dtTo))
else dateRanges ()
end;
end;
/
Запуск с тестовыми данными из этого ответа даст ожидаемый результат:
with testdata (date_from, date_to) as ( /* здесь тестовые данные */ )
select splited.*
from testdata td
cross join splitDateRangeByTimePoint (
dr=>dateRange (date_from, date_to), tp=>'00:00:00') splited;
DTFROM DTTO
------------------- -------------------
2020-04-05 23:30:29 2020-04-06 00:00:00
2020-04-06 00:00:01 2020-04-06 00:00:29