Как объединить две версионные таблицы? - PullRequest
0 голосов
/ 09 марта 2020

Существует две таблицы:

Таблица1 (id, p1, p2, date_from, date_to):

(1, 'z', 55, '01.05.2010 12:30:20', '17.05.2010 13:10:14'),
(1, 'c', null, '17.05.2010 13:10:15', '18.01.2010 04:13:15'),
(1, 'c', 25, '18.01.2010 04:13:16', '01.01.9999 00:00:00');

Table2 (id, p3, date_from, date_to):

(1, 15, '01.04.2010 12:30:20', '02.05.2010 13:10:14'),
(1, 35, '02.05.2010 13:10:15', '01.01.9999 00:00:00');

Необходимо, чтобы при объединении 2 таблиц были поля, содержащие историю изменений каждого параметра. То есть:

Выбор (id, p1, p2, p3, date_from, date_to):

(1, null, null, 10, '01.04.2010 12:30:20', '01.05.2010 12:30:19'),
(1, 'z', 55, 15, '01.05.2010 12:30:20', '02.05.2010 13:10:14'),
(1, 'z', 55, 35, '02.05.2010 13:10:15', '17.05.2010 13:10:14'),
(1, 'c', null, 35, '17.05.2010 13:10:15', '18.01.2010 04:13:15'),
(1, 'c', 25, 35, '18.01.2010 04:13:16', '01.01.9999 00:00:00');

Где записи из двух таблиц не перекрываются во времени (или части времени), должен быть выведен ноль.

Пока я сделал:

select 
    a.id, 
    case 
        when a.date_to between b.date_from and b.date_to 
            or a.date_from between b.date_from and b.date_to 
        then p1 
    end as p1,
    case 
        when a.date_to between b.date_from and b.date_to 
            or a.date_from between b.date_from and b.date_to 
        then p2 
    end as p2, 
    p3, 
    a.date_from as af, 
    b.date_from as bf, 
    a.date_to as at, 
    b.date_to as bt 
from 
    Table1 a 
    left join Table2 b 
on 
    a.id=b.id 
    and (b.date_from between a.date_from and a.date_to 
         or a.date_from between b.date_from and b.date_to)

Ответы [ 2 ]

2 голосов
/ 09 марта 2020

Вы можете получить желаемый результат, сначала вычислив все диапазоны для каждого значения id, используя последовательность CTE:

WITH dates_from AS (
  SELECT id, date_from FROM Table1
  UNION
  SELECT id, date_to + interval '1 second' FROM Table1
  UNION
  SELECT id, date_from FROM Table2
  UNION
  SELECT id, date_to + interval '1 second' FROM Table2
),
dates_to AS (
  SELECT id, date_to FROM Table1
  UNION
  SELECT id, date_from - interval '1 second' FROM Table1
  UNION
  SELECT id, date_to FROM Table2
  UNION
  SELECT id, date_from - interval '1 second' FROM Table2
),
ranges AS (
  SELECT df.id, date_from, MIN(date_to) AS date_to
  FROM dates_from df
  JOIN dates_to dt ON dt.id = df.id AND dt.date_to > df.date_from
  GROUP BY df.id, date_from
)
SELECT *
FROM ranges

Для ваших данных выборки (с настройкой, чтобы сделать to дата в строке 2 на Table1 больше, чем from дата), это дает:

id  date_from               date_to
1   2010-05-17 13:10:15     2011-01-18 04:13:15
1   2010-05-01 12:30:20     2010-05-02 13:10:14
1   2010-04-01 12:30:20     2010-05-01 12:30:19
1   2010-05-02 13:10:15     2010-05-17 13:10:14
1   2011-01-18 04:13:16     9999-01-01 00:00:00

Затем эту таблицу можно LEFT JOIN преобразовать в обе таблицы (в перекрывающихся диапазонах), чтобы извлечь соответствующие p1, p2 и p3 значения для каждого диапазона:

SELECT r.id,
       t1.p1, t1.p2, t2.p3,
       r.date_from, r.date_to
FROM ranges r
LEFT JOIN Table1 t1 ON t1.id = r.id AND t1.date_from <= r.date_to and t1.date_to >= r.date_from
LEFT JOIN Table2 t2 ON t2.id = r.id AND t2.date_from <= r.date_to and t2.date_to >= r.date_from
ORDER BY r.id, r.date_from

Выход:

id  p1  p2  p3  date_from               date_to
1           15  2010-04-01 12:30:20     2010-05-01 12:30:19
1   z   55  15  2010-05-01 12:30:20     2010-05-02 13:10:14
1   z   55  35  2010-05-02 13:10:15     2010-05-17 13:10:14
1   c       35  2010-05-17 13:10:15     2011-01-18 04:13:15
1   c   25  35  2011-01-18 04:13:16     9999-01-01 00:00:00

Демонстрация (включая значения за секунду id) на dbfiddle

0 голосов
/ 09 марта 2020

Попробуйте так:

select COALESCE(t1.id,t2.id) as id,
t1.p1,t1.p2,t2.p3,
COALESCE(t1.date_from,t2.date_from) as date_from,
COALESCE(t1.date_to,t2.date_to) as date_to
from Table1 t1
FULL OUTER JOIN Table2 t2 ON t1.id = t2.id and t1.date_from= t2.date_from and t1.date_to= t2.date_to;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...