Oracle: задачка на историчность.
теперь интервалы из результата твоего примера вычти из интервалов, находящихся в T примерно таким же запросом, и всем интервалам из полученной разности присвой (VAL, NULL).
То есть историчность должна содержать все время, покрываемое T, но при этом интервалы могут быть разбиты на более мелкие,Если периоды сравнительно небольшие, то проще сначала получить плотный временной ряд.
чтобы можно было сопоставить VAL2.
Например так
with
t as
(
select '1' id, 'a' val, 1 sd, 1 ed from dual
union
select '1' id, 'b' val, 2 sd, 5 ed from dual
union
select '1' id, 'c' val, 6 sd, 10 ed from dual
union
select '1' id, 'd' val, 11 sd, 20 ed from dual
),
t2 as
(
select '1' id, 'A' val2, 1 sd, 3 ed from dual
union
select '1' id, 'A' val2, 4 sd, 7 ed from dual
union
select '1' id, 'D' val2, 9 sd, 12 ed from dual
union
select '1' id, 'E' val2, 13 sd, 200 ed from dual
),
t3 as
(select level dt from dual connect by level <= (select max(ed) from t))
select t.id, t.val, t2.val2, dt
from t3
join t on (t3.dt between t.sd and t.ed)
left join t2 on (t3.dt between t2.sd and t2.ed)
order by 1, 4
Потом при необходимости можно убрать повторяющиеся значения.
with
t2 as
(
select '1' id, 'A' val2, 1 sd, 3 ed from dual
union
select '1' id, 'A' val2, 4 sd, 7 ed from dual
union
select '1' id, 'D' val2, 9 sd, 12 ed from dual
union
select '1' id, 'E' val2, 13 sd, 200 ed from dual
),
t2_line
as
(
select id, val2, sd, 'S' typ from t2
union all
select id, null, ed+1 , 'E' from t2
),
t2_dense
as
(
select
id, val2, sd, lead(sd) over (partition by id order by sd, typ)-1 ed
from t2_line
)
select * from t2_dense where ed >= sd;
Как раз собирался сегодня подумать, как таким способом делать (с connect by плохо дружу), - а тут раз и ответ
Большое спасибо!
Проверил - результат не совсем тот, что ожидал.
В первом случае пересекаемые интервалы, во втором - история T расширяется не только имеющиеся интервалы
в этой таблице, но и дополняет их историчностью T2, т.е. для T нет строки с действием 100 (и в результате ее быть
не должно), но она имеется Буду дальше копать.
во втором - история T расширяется не только имеющиеся интервалыЧего-то я не понял твою проблему
в этой таблице, но и дополняет их историчностью T2, т.е. для T нет строки с действием 100 (и в результате ее быть
не должно), но она имеется
with t as
(
select '1' id, 'a' val, 1 sd, 1 ed from dual
union
select '1' id, 'b' val, 2 sd, 5 ed from dual
union
select '1' id, 'c' val, 6 sd, 10 ed from dual
union
select '1' id, 'd' val, 11 sd, 20 ed from dual
),t2 as
(
select '1' id, 'A' val2, 1 sd, 3 ed from dual
union
select '1' id, 'A' val2, 4 sd, 7 ed from dual
UNION
select '1' id, 'D' val2, 9 sd, 12 ed from dual
union
select '1' id, 'E' val2, 13 sd, 200 ed from dual
),
t2_line
as
(
select id, val2, sd, 'S' typ from t2
union all
select id, null, ed+1 , 'E' from t2
),
t2_dense
as
(
select
id, val2, sd, lead(sd) over (partition by id order by sd, typ)-1 ed
from t2_line
)
select t1.id, t1.val, t2.val2, greatest(t1.sd, t2.sd) sd, least(t1.ed, t2.ed) ed
from t t1
inner join t2_dense t2
ON (t2.ed >= t2.sd
and t1.ed >= t2.sd
and t2.ed >= t1.sd);
Какая из этих строк лишняя?
ID VAL VAL2 SD ED
1 a A 1 1
1 b A 2 3
1 b A 4 5
1 c A 6 7
1 c 8 8
1 c D 9 10
1 d D 11 12
1 d E 13 20
P.S. Единственное у T2 надо вставить еще два промежутка - (от минус бесконечности до минимального sd) и (от максимального ed до плюс бесконечности), поскольку иначе историчность T2 будет урезана по (min t2.sd, mas t2.ed)
Единственное у T2 надо вставить еще два промежутка - (от минус бесконечности до минимального sd) и (от максимального ed до плюс бесконечности), поскольку иначе историчность T2 будет урезана по (min t2.sd, mas t2.ed)Лучше и проще добавить в t2_line
Как-то так:
union all select distinct id, null, :min_date 'S' from t2
union all select distinct id, null, :max_date 'E' from t2
Так и сделал уже
Оставить комментарий
0000
Есть две таблицы:Таблица T: ID, VAL, SD (=START_DATE), ED (=END_DATE)
Таблица T2: ID, VAL2, SD(=START_DATE), ED (=END_DATE)
Таблица T ссылается на T2 по ID. Каждая строка в обоих таблицах действует в пределах интервала, задаваемого START_DATE и END_DATE.
Требуется построить результирующее множество, содержащее ответ, что в такой-то такой то промежуток у ID был VAL и VAL2 или ID имел VAL и пусто (если в T2 на данный момент действующей строки не было).
То есть историчность должна содержать все время, покрываемое T, но при этом интервалы могут быть разбиты на более мелкие,
чтобы можно было сопоставить VAL2.
Пример для Oracle (пустые значение не обрабатываются - а надо; напр. с 7 по 8 значение есть, а в результате нет - надо c, NULL)