powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Oracle [игнор отключен] [закрыт для гостей] / SCD type2 again
2 сообщений из 2, страница 1 из 1
SCD type2 again
    #39366414
kaldorey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добрый день!
Есть таблички, неисторичные, с размерностью не более 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
SCD type2 again
    #39367033
ora601
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kaldorey,

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


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