123 1900-01-01 2012-07-04 Улица Строителей 5
123 2012-07-05 2015-03-01 Ленинградский проспект, 21
123 2015-03-02 9999-12-31 Мосфильмовская ул, 12
… … … …
Client_id Start_dt End_dt Client_job
123 1900-01-01 2007-02-11 ПАО Аэрофлот
123 2007-02-12 2013-11-22 ПАО ВТБ
123 2015-03-02 9999-12-31 Мосфильмовская ул, 12
… … … …
Их надо объединить так, чтоб получилась такая таблица
Client_id Start_dt End_dt Client_addr Client_job
123 1900-01-01 2007-02-11 Улица Строителей 5 ПАО Аэрофлот
123 2007-02-12 2012-07-04 Улица Строителей 5 ПАО ВТБ
123 2012-07-05 2013-11-22 Ленинградский проспект, 21 ПАО ВТБ
… … … … …
Т.е. учитывая временной диапазон, как к этому можно подступиться?
Аккуратно написать [FULL] JOIN? Или здесь есть что-то, чего я не вижу?
там просто надо пересечение интервалов дат, кроме связи по client_id
Ну да, аккуратно записать это пересечение и выражения для start, end в результате, и всё... нет?
ну дальше только автор может ответить. по идее всё
Вот не совсем понятно как записать пересечение и выражения для start и end 🤔
Пересечение отрезков числовой прямой проходят на... геометрии в 7 классе, кажется? ;) Выражения записываются аналогично.
Хотя подождите. Это же зависит от того, какой результат Вам нужен — может, это вообще не на пересечения задача.
А тут разве не так: Либо начало одного диапазона входит в другой либо конец? Вроде так должно получится… on client_id1 = client_id2 and (start1 between start2 and end2 or end1 between start2 and end2)
(Прочитал исходный вопрос внимательнее) Да вот неизвестно, в чём тут задача, и даже непонятно, что значат исходные данные, мне кажется.
ну как я понял, необходимо определить какой адрес какой организации в какой период времени принадлежал, а там кто знает )))
Там две таблицы. И вторая, судя по всему, про Client_job, но в этом поле есть и значение "Мосфильмовская ул, 12". ;) Кроме того, непонятно, бывают ли разрывы в данных (когда у клиента нет адреса или работы), а если нет — то зачем там два поля с датами. В общем, это у автора нужно спрашивать...
Спасибо, таким запросом проблема решилась) select a.client_id, case when a.start_dt between j.start_dt and j.end_dt then a.start_dt else j.start_dt end start_dt, case when a.end_dt between j.start_dt and j.end_dt then a.end_dt else j.end_dt end start_dt, client_addr, client_job from temp.t_client_addr a join temp.t_client_job j on a.client_id = j.client_id and (a.start_dt between j.start_dt and j.end_dt or a.end_dt between j.start_dt and j.end_dt)
Как-то так: postgres=# create table addr (id int, start_dt date, end_dt date, addr text); CREATE TABLE postgres=# create table job (id int, start_dt date, end_dt date, job text); postgres=# insert into addr values (123, '1900-01-01', '2012-07-04', 'Улица Строителей 5'), (123, '2012-07-05', '2015-03-01', ' Ленинградский проспект, 21'), (123, '2015-03-02', '9999-12-31', 'Мосфильмовская ул, 12'); INSERT 0 3 postgres=# insert into job values (123, '1900-01-01', '2007-02-11', 'ПАО Аэрофлот'), (123, '2007-02-12', '2013-11-22', 'ПАО ВТБ'), (123, '2013-11-23', '9999-12-31', 'Роскосмос'); INSERT 0 3 postgres=# select addr.id, GREATEST(addr.start_dt, job.start_dt) as start_dt, LEAST(addr.end_dt, job.end_dt) as end_dt, addr, job from addr join job on addr.id = job.id and GREATEST(addr.start_dt, job.start_dt) < LEAST(addr.end_dt, job.end_dt) order by start_dt; id | start_dt | end_dt | addr | job -----+------------+------------+-----------------------------+-------------- 123 | 1900-01-01 | 2007-02-11 | Улица Строителей 5 | ПАО Аэрофлот 123 | 2007-02-12 | 2012-07-04 | Улица Строителей 5 | ПАО ВТБ 123 | 2012-07-05 | 2013-11-22 | Ленинградский проспект, 21 | ПАО ВТБ 123 | 2013-11-23 | 2015-03-01 | Ленинградский проспект, 21 | Роскосмос 123 | 2015-03-02 | 9999-12-31 | Мосфильмовская ул, 12 | Роскосмос (5 rows) postgres=# Но это, если разрывов нет. Если разрывы есть, то .... как-будто бы asof join подошёл, которого нету в postgresql. Поэтому придётся эмулировать его оконными функциями.
Интересное решение, спасибо)
А вот решение с разрывами (только для работы, для адреса можно сделать аналогично): postgres=# insert into addr values (123, '1900-01-01', '2012-07-04', 'Улица Строителей 5'), (123, '2012-07-05', '2015-03-01', ' Ленинградский проспект, 21'), (123, '2015-03-02', '9999-12-31', 'Мосфильмовская ул, 12'); INSERT 0 3 postgres=# insert into job values (123, '1900-01-01', '2007-02-11', 'ПАО Аэрофлот'), (123, '2007-02-28', '2013-11-22', 'ПАО ВТБ'), (123, '2015-11-17', '2017-12-31', 'Роскосмос'); INSERT 0 3 postgres=# with not_work as ( select * from ( select job.id, lag(end_dt, 1, '1970-01-01') over (partition by id order by start_dt) + 1 as start_dt, start_dt - 1 as end_dt, 'радовался жизни' as job from job ) as t where start_dt <= end_dt union all select job.id, max(end_dt) + 1 as start_dt, '9999-12-31' as end_dt, 'радовался жизни до её конца' as job from job group by job.id ), all_work as ( select * from not_work union all select * from job ) select addr.id, GREATEST(addr.start_dt, w.start_dt) as start_dt, LEAST(addr.end_dt, w.end_dt) as end_dt, addr, job from addr join all_work as w on addr.id = w.id and GREATEST(addr.start_dt, w.start_dt) < LEAST(addr.end_dt, w.end_dt) order by start_dt; id | start_dt | end_dt | addr | job -----+------------+------------+-----------------------------+----------------------------- 123 | 1900-01-01 | 2007-02-11 | Улица Строителей 5 | ПАО Аэрофлот 123 | 2007-02-12 | 2007-02-27 | Улица Строителей 5 | радовался жизни 123 | 2007-02-28 | 2012-07-04 | Улица Строителей 5 | ПАО ВТБ 123 | 2012-07-05 | 2013-11-22 | Ленинградский проспект, 21 | ПАО ВТБ 123 | 2013-11-23 | 2015-03-01 | Ленинградский проспект, 21 | радовался жизни 123 | 2015-03-02 | 2015-11-16 | Мосфильмовская ул, 12 | радовался жизни 123 | 2015-11-17 | 2017-12-31 | Мосфильмовская ул, 12 | Роскосмос 123 | 2018-01-01 | 9999-12-31 | Мосфильмовская ул, 12 | радовался жизни до её конца (8 rows) postgres=#
Обсуждают сегодня