Гость
Map
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Доп. действия во время MERGE / 25 сообщений из 34, страница 1 из 2
04.10.2021, 12:22
    #40101756
verter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
Делаю обыкновенный MERGE:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
    MERGE INTO TBL_DEST d
    USING (
                select ...
                from TBL_SRC
          ) s
    ON
       (d.f1 = s.f1 AND d.f2 = s.f2 AND ...)
    WHEN MATCHED THEN
      UPDATE SET
         d.f3= s.f3,
         d.f4 = ...
      WHERE d.f5 ...
    WHEN NOT MATCHED THEN
      INSERT
        (d.f1,d.f2,....)
      VALUES
        (s.f1,s.f2,...)
;


Если мне надо что то делать дополнительно, например, делать insert'ы в какую-нибудь ещё таблицу при UPDATE и при INSERT этого MERGE, то как это лучше сделать?

Что то примерно такое надо:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
    MERGE INTO TBL_DEST d
    USING (
                select ...
                from TBL_SRC
          ) s
    ON
       (d.f1 = s.f1 AND d.f2 = s.f2 AND ...)
    WHEN MATCHED THEN
      UPDATE SET
         d.f3= s.f3,
         d.f4 = ...
      WHERE d.f5 ...
      INSERT INTO TBL_LOG1 VALUES(...)
    WHEN NOT MATCHED THEN
      INSERT
        (d.f1,d.f2,....)
      VALUES
        (s.f1,s.f2,...)
      INSERT INTO TBL_LOG2 VALUES(...)
;
...
Рейтинг: 0 / 0
04.10.2021, 13:19
    #40101776
Stax
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
verter

Если мне надо что то делать дополнительно

в триггере insert ...

.....
stax
...
Рейтинг: 0 / 0
04.10.2021, 13:28
    #40101780
Anton_Demin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
verter,

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
FOR  i IN (/*SELECT MATCHED ROWS*/) 
   LOOP 
      INSERT / UPDATE / DELETE
   END LOOP;

FOR  i IN (/*SELECT NOT MATCHED ROWS*/) 
   LOOP 
      INSERT / UPDATE / DELETE
   END LOOP;
...
Рейтинг: 0 / 0
04.10.2021, 14:27
    #40101808
verter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
Stax
verter

Если мне надо что то делать дополнительно

в триггере insert ...

.....
stax


в триггере то понятно, но, к сожалению, есть ограничение на разработку, нельзя использовать триггеры.
...
Рейтинг: 0 / 0
04.10.2021, 14:28
    #40101809
verter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
Anton_Demin
verter,

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
FOR  i IN (/*SELECT MATCHED ROWS*/) 
   LOOP 
      INSERT / UPDATE / DELETE
   END LOOP;

FOR  i IN (/*SELECT NOT MATCHED ROWS*/) 
   LOOP 
      INSERT / UPDATE / DELETE
   END LOOP;



Объём таблиц очень большой, циклами будет очень медленно.
...
Рейтинг: 0 / 0
04.10.2021, 14:55
    #40101816
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
verterесть ограничение на разработку

Значит спрашивай того, кто эти ограничения установил. У него же наверняка был
план...
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
04.10.2021, 16:12
    #40101846
barrabas
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
А если сделать функцию, в которую нужные для вставки параметры и она возвращает нужное значение для поля в мердже. так сработает?


Код: plsql
1.
2.
3.
4.
5.
6.
WHEN MATCHED THEN
      UPDATE SET
         d.f3= insertlog(s.f3, ....),
         d.f4 = ...
      WHERE d.f5 ...
      
...
Рейтинг: 0 / 0
04.10.2021, 17:13
    #40101873
PuM256
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
barrabas,

И получишь ORA-14551: cannot perform a DML operation inside a query
...
Рейтинг: 0 / 0
04.10.2021, 17:23
    #40101876
barrabas
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
точно?
попробовал быстро на инсерте не получил

Код: 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.
create table TMP_A1(a1 number, a2 varchar2(64))
/
create table TMP_L1(a1 number, a2 varchar2(64))
/
 

create or replace function TestINS(a number, b varchar2) return number
is
begin
   insert into TMP_L1(A1, A2)
   values(a, b);
   return a;
end;
/


delete tmp_a1;
delete tmp_l1;

insert into TMP_A1(a1, a2)
select TestINS(SEQ__A.NEXTVAL, 'xxx'), 'aaa'
  from DUAL
/


select * from TMP_A1
/
select * from TMP_L1  
/  




Код: plaintext
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.
delete tmp_a1;

1 row deleted

delete tmp_l1;

1 row deleted

insert into TMP_A1(a1, a2)
select TestINS(SEQ__A.NEXTVAL, 'xxx'), 'aaa'
  from DUAL
/

1 row inserted

select * from TMP_A1
/

        A1 A2
---------- ----------------------------------------------------------------
   1795025 aaa
select * from TMP_L1
/

        A1 A2
---------- ----------------------------------------------------------------
   1795025 xxx
...
Рейтинг: 0 / 0
04.10.2021, 17:39
    #40101883
barrabas
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
merge тоже без ошибки
по условию доп действия с другой таблицей же (INSERT INTO TBL_LOG1 VALUES(...))

Код: 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.
create table TMP_A1(a1 number, a2 varchar2(64))
/
create table TMP_L1(d date, a1 number, log1 varchar2(64))
/
 

create or replace function TestINS(a2 varchar2, a1 number, log1 varchar2) return varchar2
is
begin
   insert into TMP_L1(D, a1, log1)
   values(sysdate, a1, log1);
   return a2;
end;
/



merge into tmp_a1 d
using (select 11 a1, 'aaa' a2, 'mylog' log1 from DUAL) s
on (s.a1 = d.a1)
WHEN MATCHED THEN
      UPDATE SET
         d.a2 = TestINS(s.a2, s.a1, s.log1)
    WHEN NOT MATCHED THEN
      INSERT
        (d.a1,d.a2)
      VALUES
        (s.a1, TestINS(s.a2, s.a1, s.log1))
...
Рейтинг: 0 / 0
04.10.2021, 17:42
    #40101885
verter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
barrabas
А если сделать функцию, в которую нужные для вставки параметры и она возвращает нужное значение для поля в мердже. так сработает?


Код: plsql
1.
2.
3.
4.
5.
WHEN MATCHED THEN
      UPDATE SET
         d.f3= insertlog(s.f3, ....),
         d.f4 = ...
      WHERE d.f5 ...



идея классная! но будет ли быстро работать на больших таблицах?
...
Рейтинг: 0 / 0
04.10.2021, 17:43
    #40101886
barrabas
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
если нужно еще и с таблицами участвующими в мердже, то думаю можно через временные таблицы или коллекции в пакетных переменных (по типу обхода ошибки с мутацией). накопить что должен сделать и сделать после мерджа сразу.
...
Рейтинг: 0 / 0
04.10.2021, 17:45
    #40101887
barrabas
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
verter,

все зависит что именно нужно.
может реально накопить в памяти в коллекции, которая заполняется в функции, а потом вставить через forall.

попробуй по разному
...
Рейтинг: 0 / 0
04.10.2021, 17:47
    #40101889
barrabas
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
barrabas
verter,

все зависит что именно нужно.
может реально накопить в памяти в коллекции, которая заполняется в функции, а потом вставить через forall.

попробуй по разному

если очень много, то forall прям в функции по определенному кол-ву записей с очисткой коллекции, а потом в конце остатки.
...
Рейтинг: 0 / 0
07.10.2021, 14:04
    #40102700
verter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
barrabas,

Я попробовал сделать в MERGE запись в лог функцией.
Всё сработало хорошо, спасибо.

НО!

Почему то вызов функции срабатывает 2 раза.
Соответственно и в таблице лога появляется 2-е одинаковые записи.

Вот я выполняю MERGE:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
merge into tmp_a1 d
using (select 11 a1, 'aaa' a2, 'mylog' log1 from DUAL) s
on (s.a1 = d.a1)
WHEN MATCHED THEN
      UPDATE SET
         d.a2 = TestINS(s.a2, s.a1, s.log1)
    WHEN NOT MATCHED THEN
      INSERT
        (d.a1,d.a2)
      VALUES
        (s.a1, TestINS(s.a2, s.a1, s.log1))


Допустим срабатывает блок с INSERT, т.е. WHEN NOT MATCHED
Но в TMP_L1 появляются 2-е записи, т.е. TestINS() срабатывает 2 раза.
Как такое может быть?
Отдельно TestINS() вызывал - записывает 1 раз.
...
Рейтинг: 0 / 0
07.10.2021, 14:08
    #40102703
barrabas
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
verter
barrabas,

Я попробовал сделать в MERGE запись в лог функцией.
Всё сработало хорошо, спасибо.

НО!

Почему то вызов функции срабатывает 2 раза.
Соответственно и в таблице лога появляется 2-е одинаковые записи.

Вот я выполняю MERGE:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
merge into tmp_a1 d
using (select 11 a1, 'aaa' a2, 'mylog' log1 from DUAL) s
on (s.a1 = d.a1)
WHEN MATCHED THEN
      UPDATE SET
         d.a2 = TestINS(s.a2, s.a1, s.log1)
    WHEN NOT MATCHED THEN
      INSERT
        (d.a1,d.a2)
      VALUES
        (s.a1, TestINS(s.a2, s.a1, s.log1))


Допустим срабатывает блок с INSERT, т.е. WHEN NOT MATCHED
Но в TMP_L1 появляются 2-е записи, т.е. TestINS() срабатывает 2 раза.
Как такое может быть?
Отдельно TestINS() вызывал - записывает 1 раз.

ну видимо оракл вычисляет значение функции для всего мерджа заранее. можно попробовать deterministic указать у функции или через пакетную переменную сделать проверку на некий уникальный ID вызова. короче, выкрутится то можно но будет мостр )
вместо пакетной переменной можно sys_context еще попробовать.
на вход что-то уникальное для записи, например склейку полей из ON. сохранять в контекст/переменную и проверять что изменилась, только тогда писать в лог
...
Рейтинг: 0 / 0
07.10.2021, 14:15
    #40102708
barrabas
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
для интереса, если для инсерта и апдейте сделать функции с разным именем, тоже 2 раза будет?
...
Рейтинг: 0 / 0
07.10.2021, 14:42
    #40102730
verter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
barrabas
для интереса, если для инсерта и апдейте сделать функции с разным именем, тоже 2 раза будет?


deterministic помог избавиться от двойной записи, спасибо!

Но есть ещё одна проблема, которую я не сразу заметил, потому что проверял по отдельности вызовы TestINS() - при апдейте отдельно и при инсёрте отдельно. А теперь когда вставил вызов TestINS() в оба, то после мержа появляются записи после инсёрта и апдейта, несмотря на то, что срабатывает какая то одна из секций мержа - либо MUCHED либо NOT MUCHED. Я проверял когда MUCHED, т.е. должен был сработать вызов TestINS() только 1 раз с значениями для апдейта, но сработало 2 раза - и для апдейта и для инсёрта.
Т.о. Oracle до мержа вызывает функции из обоих секций каким то образом.
Пробывал сделать отдельные функции TestINS_on_I и TestINS_on_U - не помогает, срабатывают одновременно обе.
Ну вот как так?
...
Рейтинг: 0 / 0
07.10.2021, 14:46
    #40102734
verter
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
ну и соответственно если убрать determenistic, то в логе будут 4 записи - 2 для инсёрта и 2 для апдейта хотя в результате мержа происходит обновление 1 записи
...
Рейтинг: 0 / 0
07.10.2021, 14:54
    #40102741
barrabas
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
verter,

проверять уникальность тогда остаётся
в USING сделать поле с sys_guid или что-то униканое.

передавать в функцию, в ней проверять в контексте или переменной пакетной, есть ли такое значение, если нет, то записываем в контекст его и пишем в лог. если происходит повторный вызов, мы видим что такая запись уже прилетала в функции и пропускам.
учесть что у апдейта может быть WHERE, т.е. в в функцию нужно передать флаг скип сразу вычислив через case например
...
Рейтинг: 0 / 0
07.10.2021, 14:57
    #40102744
barrabas
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
я вообще такое решение не применял никогда. просто интересно как задача показалась.
...
Рейтинг: 0 / 0
07.10.2021, 15:54
    #40102769
oragraf
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
verter,

1. Разделить insert и update
2 insert... returning ... bulk collect into...
3. update ... returning ... bulk collect into...
4. insert into log....
...
Рейтинг: 0 / 0
07.10.2021, 16:14
    #40102780
barrabas
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
если отвлечься от задачи "действия во время merge".

а надо мёрджить реально большие таблицы с миллионами записей и нет жесткого требования закомитить все разом, то я бы еще подробил по дням/месяцам/годам (или что там есть и сколько в данных в порциях) + dbms_application_info.set_session_longops.
ползунок в GUI или проценты в логе, они успокаивают что-ли ...
...
Рейтинг: 0 / 0
07.10.2021, 16:16
    #40102781
barrabas
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
ну и dbms_parallel_execute или потоки с клиента
...
Рейтинг: 0 / 0
07.10.2021, 17:22
    #40102808
Stax
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Доп. действия во время MERGE
verter,

В древних версиях, я придерживался такого правила

"Количество срабатываний функции в SQL не гарантировано"

мне даже VB пытался обяснить, но я не все понял

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


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