Вы можете быстро выполнить эту работу с типом данных Teradata PERIOD. Период - это диапазон дат или временных меток. В качестве аргументов требуется две даты или временные метки: первая для даты начала и вторая для даты окончания (до, но не включая).
В вашем случае мы преобразуем ваши End_Date
и P_INTERSECT
в периоды, чтобы выполнить соединение. Мы будем использовать функцию Period, чтобы найти перекрывающиеся периоды, к которым мы присоединяемся.SELECT attr1, attr2, /*pull the BEGIN of the intersected period*/ BEGIN(t1.validperiod P_INTERSECT t2.validperiod) as startdate, /*pull the END of the intersected period (subtracting a day since period end dates are "up to but not including")*/ PRIOR(END(t1.validperiod P_INTERSECT t2.validperiod)) as enddate FROM (SELECT abc.*, PERIOD(start_date, NEXT(end_date)) as validperiod FROM abc) t1 INNER JOIN (SELECT pqr.*, PERIOD(start_Date, NEXT(end_date)) as validperiod FROM pqr) t2 ON t1.id = t2.id /* * Now P_INTERSECT our two periods and look for Non-Null intersections * The intersection is the date range where the two periods overlap */ AND t1.validperiod P_INTERSECT t2.validperiod IS NOT NULL;
t1.validperiod P_INTERSECT t2.validperiod P_INTERSECT t3.validperiod IS NOT NULL
Есть несколько бонусов, которые мы получаем здесь:
- Логика чиста и проста. Нет тестов для max (start_date) и min (end_date) с вложенными операциями CASE и всем этим ужасом
- Если вам нужно присоединиться к третьей таблице, просто преобразуйте ее начальную и конечную дату в validperiod и присоединитесь к Simple simple.
create table abc ( id integer, attr1 varchar(3), start_date date, end_date date) PRIMARY INDEX(ID); create table PQR ( id integer, attr2 varchar(3), start_date date, end_date date) PRIMARY INDEX(ID); INSERT INTO abc VALUES(1,'LMN','2017-01-01','2017-02-28'); INSERT INTO abc VALUES(1,'HGI','2017-02-28','2017-03-15'); INSERT INTO abc VALUES(1,'STI','2017-03-15','2099-12-31'); INSERT INTO PQR VALUES(1,'KLM','2017-01-01','2017-01-20'); INSERT INTO PQR VALUES(1,'TLF','2017-01-20','2017-04-04'); INSERT INTO PQR VALUES(1,'SNQ','2017-04-04','2099-12-31'); select a.id,a.attr1,p.attr2, cast(greatest(cast(a.start_date as int),cast(p.start_date as int)) as date)start_date, cast(least(cast(a.end_date as int),cast(p.end_date as int)) as date)end_date from abc a inner join pqr p on a.id=p.id where a.start_date between p.start_date and p.end_date or a.end_date between p.start_date and p.end_date order by 4;
- Есть несколько других действительно полезных функций, которые основаны на сроках, что сделает эту работу быстрой. Например, NORMALIZE объединяет несколько записей на основе составного ключа и перекрытия и периодов встреч.
Наконец, как правило, когда я создаю таблицы, и эта таблица имеет дату начала и дату окончания, я ВСЕГДА создаю новое поле с именем validperiod и загружаю его, как мы делаем в этих подзапросах. Тогда вам не нужно конвертировать в период, чтобы ваши объединения были дружелюбны. Просто возьмите уже сохраненный столбец validperiod и запустите P_INTERSECTing. Он принимает всю работу из других уродливых объединений и выбирает.