powered by simpleCommunicator - 2.0.30     © 2024 Programmizd 02
Map
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Доп. действия во время MERGE
25 сообщений из 34, страница 1 из 2
Доп. действия во время MERGE
    #40101756
verter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Делаю обыкновенный 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
Доп. действия во время MERGE
    #40101776
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
verter

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

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

.....
stax
...
Рейтинг: 0 / 0
Доп. действия во время MERGE
    #40101780
Фотография 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
Доп. действия во время MERGE
    #40101808
verter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Stax
verter

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

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

.....
stax


в триггере то понятно, но, к сожалению, есть ограничение на разработку, нельзя использовать триггеры.
...
Рейтинг: 0 / 0
Доп. действия во время MERGE
    #40101809
verter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Доп. действия во время MERGE
    #40101816
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
verterесть ограничение на разработку

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


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

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

Код: 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
Доп. действия во время MERGE
    #40101883
Фотография barrabas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Доп. действия во время MERGE
    #40101885
verter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
barrabas
А если сделать функцию, в которую нужные для вставки параметры и она возвращает нужное значение для поля в мердже. так сработает?


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



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

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

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

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

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

если очень много, то forall прям в функции по определенному кол-ву записей с очисткой коллекции, а потом в конце остатки.
...
Рейтинг: 0 / 0
Доп. действия во время MERGE
    #40102700
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 раз.
...
Рейтинг: 0 / 0
Доп. действия во время MERGE
    #40102703
Фотография barrabas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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
Доп. действия во время MERGE
    #40102708
Фотография barrabas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
для интереса, если для инсерта и апдейте сделать функции с разным именем, тоже 2 раза будет?
...
Рейтинг: 0 / 0
Доп. действия во время MERGE
    #40102730
verter
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
barrabas
для интереса, если для инсерта и апдейте сделать функции с разным именем, тоже 2 раза будет?


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

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

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

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

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

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

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

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

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

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


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