Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Oracle [игнор отключен] [закрыт для гостей] / SCD type2 again / 2 сообщений из 2, страница 1 из 1
14.12.2016, 09:50
    #39366414
kaldorey
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
SCD type2 again
Добрый день!
Есть таблички, неисторичные, с размерностью не более 200к строк.
Хочется переливать таблички так, чтобы обеспечить историчность, например раз в день.
таблица table1 - это id, code, name и допустим checksum по всем отслеживаемым полям(может быть и сравнение всех столбцов, в данном топике не принципиально)
таблица table 2 - то же самое, плюс date_begin, date_end, is_actual, is_deleted

Какие действия необходимо совершить:
1) Вставить новые записи
2) Обновить существующие, если поменялись значимые столбцы
a) поставить date_end = sysdate у текущей записи
b) вставить измененную запись как новую
3) Пометить запись в table1 как удаленную, если в table2 эта запись не пришла.

Я нашел, что в mssql это делается примерно так:
Код: sql
1.
2.
3.
insert into table1
select some_cols
from (merge into table1 using(full join) .... out some_cols)


Для оракла нашел несколько вариантов, но они выполняют 2 шага из 3 в различных комбинациях.

Написал свой вариант, но, возможно, я что-то упустил, и потом правда вылезет слишком поздно.
К тому же прошлый опыт подсказывает, что либо плохо искал, либо есть нюансы, из-за чего так делать нельзя/не надо/не производительно.
Прошу оставить свое мнение или ссылки на правильный вариант

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
merge into table1 a
using
(
    select coalesce(t2.id , t1.id) id,
           t2.code,
           t2.name,
           case when c.lvl = 2 then 'upd'
                               when t2.rowid is null then 'del'
                               when t2.checksum = t1.checksum then 'dummy'
                               else 'ins'
           end flag,
           t2.checksum
    from table2 t2
  full join
    (select id, checksum  from table1 where is_active = 1) t1  
  on t2.id = t1.id
   join lateral(select level lvl 
               from dual 
               connect by level <= case when t2.checksum != t1.checksum
                                     then sign(t1.id) + sign(t2.id) end) c on 1=1
) b
on (a.id = b.id and b.flag in ('upd', 'del', 'dummy'))
when matched then
	update
  set date_end = sysdate,
      is_active = 0,
      is_deleted = case when b.flag = 'del' then 1 else 0 end
  where  a.is_active = 1
    and b.flag != 'dummy'
when not matched then
	insert (id, code, name, checksum, date_begin, date_end, is_active, is_deleted)
  values (b.id, b.code, b.name, b.checksum, sysdate, date '3000-12-31', 1, 0);
...
Рейтинг: 0 / 0
14.12.2016, 16:54
    #39367033
ora601
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
SCD type2 again
kaldorey,

нормально, латерал зачем только.
...
Рейтинг: 0 / 0
Форумы / Oracle [игнор отключен] [закрыт для гостей] / SCD type2 again / 2 сообщений из 2, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]