Oracle sql merge для вставки и удаления, но не обновления

есть ли способ использовать oracle merge для вставки и удаления, но не обновления?

у меня есть таблица, представляющая набор значений, связанных с одной строкой в другой таблице. Я мог бы изменить набор значений, удалив их все и добавив новый набор, или выборочно удалив некоторые и добавив другие, но я заинтересован в том, чтобы сделать его одним оператором, если это возможно.

вот рабочий пример с обновлением. Чтобы сделать эту работу, я должен был добавить dummy так что столбец был доступен для обновления, которого не было в on состояние. Есть ли способ только удалить и вставить без фиктивного столбца для обновления?

нет столбца с on условие может быть в update set списке, даже если он фактически не обновляется.

create table every_value ( the_value varchar2(32) );
create table paired_value ( the_id number, a_value varchar2(32) , dummy number default 0 );
-- the_id is a foreign_key to a row in another table

insert into every_value ( the_value ) values ( 'aaa' );
insert into every_value ( the_value ) values ( 'abc' );
insert into every_value ( the_value ) values ( 'ace' );
insert into every_value ( the_value ) values ( 'adg' );
insert into every_value ( the_value ) values ( 'aei' );
insert into every_value ( the_value ) values ( 'afk' );

-- pair ace and afk with id 3
merge into paired_value p using every_value e
on ( p.the_id = 3 and p.a_value = e.the_value )
when matched then update set dummy=dummy+1
delete where a_value not in ('ace','afk')
when not matched then insert (the_id,a_value)
values (3,e.the_value)
where e.the_value in ('ace','afk');

-- pair ace and aei with id 3
-- should remove afk, add aei, do nothing with ace
merge into paired_value p using every_value e
on ( p.the_id = 3 and p.a_value = e.the_value )
when matched then update set dummy = dummy+1
delete where a_value not in ('ace','aei')
when not matched then insert (the_id,a_value)
values (3,e.the_value)
where e.the_value in ('ace','aei');

-- pair aaa and adg with id 4
merge into paired_value p using every_value e
on ( p.the_id = 4 and p.a_value = e.the_value )
when matched then update set dummy = dummy+1
delete where a_value not in ('aaa','adg')
when not matched then insert (the_id,a_value)
values (4,e.the_value)
where e.the_value in ('aaa','adg');

select * from paired_value;

Я пробовал это в oracle 10g и, с этим sqlfiddle, oracle 11g.

2 ответов


нет, нельзя удалить строки, которые не были обновлены командой merge.
Вот документация: http://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_9016.htm

укажите DELETE where_clause для очистки данных в таблице во время заполнение или обновление. единственный строк, затронутых данной статьи строки в целевой таблице, обновляемые слиянием операция. Условие удалить где оценивает обновленное значение, а не исходное значение, которое было оценено набором обновлений... ГДЕ состояние. Если строка целевой таблицы соответствует DELETE условие, но не включено в соединение, определенное предложением ON, тогда он не удаляется. Любые триггеры delete, определенные на цели таблица будет активирована для каждого удаления строки.

Это означает, что строки должны обновления. Hovewer, вам не нужно обновлять все строки, после обновления используйте то же предложение WHERE, которое вы используете после DELETE

when matched then update set dummy=dummy
    where a_value not in ('ace','afk')
delete 
    where a_value not in ('ace','afk')

Я нашел, что вы можете установить столбец для себя:

MERGE ...
WHEN MATCHED THEN 
   UPDATE SET a_value = a_value WHERE a_value not in ('ace','afk')
   DELETE WHERE a_value not in ('ace','afk')

это отрицает необходимость фиктивного столбца.