Операция UPSERT обновляет или вставляет строку в таблицу, в зависимости от того, есть ли в таблице строка, соответствующая данным:
if table t has a row exists that has key X:
update t set mystuff... where mykey=X
else
insert into t mystuff...
Поскольку у Oracle нет конкретного оператора UPSERT, каков наилучший способ сделать это?
Оператор MERGE объединяет данные между двумя таблицами. Использование DUAL позволяет нам использовать эту команду. Обратите внимание, что это не защищено от одновременного доступа.
источник
Вышеприведенный двойной пример, который находится в PL / SQL, был великолепен, потому что я хотел сделать что-то подобное, но я хотел, чтобы это было на стороне клиента ... так вот SQL, который я использовал для отправки аналогичного оператора прямо из некоторого C #
Однако с точки зрения C # это обеспечивает более медленную скорость, чем выполнение обновления и определение, было ли затронуто строк 0, и выполнение вставки, если это так.
источник
MERGE
DELETE
INSERT
MERGE INTO mytable d USING (SELECT 1 id, 'x' name from dual) s ON (d.id = s.id) WHEN MATCHED THEN UPDATE SET d.name = s.name WHEN NOT MATCHED THEN INSERT (id, name) VALUES (s.id, s.name);
Еще одна альтернатива без проверки исключений:
источник
источник
Ни один из ответов, данных до сих пор, не является безопасным перед лицом одновременного доступа , как указано в комментарии Тима Сильвестра, и не вызовет исключений в случае гонок. Чтобы это исправить, комбинация вставки / обновления должна быть заключена в какой-то оператор цикла, чтобы в случае исключения все повторялось.
Например, вот как код Grommit может быть заключен в цикл, чтобы сделать его безопасным при одновременном запуске:
NB. В режиме транзакции
SERIALIZABLE
, который я не рекомендую, кстати, вы можете столкнуться с ORA-08177: вместо этого нельзя сериализовать доступ для исключений этой транзакции .источник
Я бы хотел, чтобы Grommit ответил, за исключением того, что он требует двойных значений. Я нашел решение, где оно может появиться один раз: http://forums.devshed.com/showpost.php?p=1182653&postcount=2
источник
INSERT (B.CILT, B.SAYFA, B.KUTUK, B.MERNIS_NO) VALUES (E.CILT, E.SAYFA, E.KUTUK, E.MERNIS_NO);
?Примечание относительно двух решений, которые предлагают:
1) Вставьте, если исключение, затем обновить,
или
2) Обновить, если sql% rowcount = 0, затем вставить
Вопрос о том, вставлять или обновлять первым, также зависит от приложения. Вы ожидаете больше вставок или больше обновлений? Тот, кто, скорее всего, добьется успеха, должен идти первым.
Если вы выберете неправильный вариант, вы получите кучу ненужных индексов. Не огромная сделка, но все еще кое-что, чтобы рассмотреть.
источник
Я использовал первый пример кода за годы. Обратите внимание не найден, а считать.
Код ниже является возможно новым и улучшенным кодом
В первом примере обновление выполняет поиск по индексу. Это необходимо для того, чтобы обновить правую строку. Oracle открывает неявный курсор, и мы используем его для переноса соответствующей вставки, поэтому мы знаем, что вставка произойдет только тогда, когда ключ не существует. Но вставка является независимой командой, и она должна выполнить второй поиск. Я не знаю внутреннюю работу команды слияния, но так как команда представляет собой единое целое, Oracle может выполнить правильную вставку или обновление с одним поиском по индексу.
Я думаю, что слияние лучше, когда вам нужно выполнить некоторую обработку, то есть взять данные из некоторых таблиц и обновить таблицу, возможно, вставив или удалив строки. Но для случая с одной строкой вы можете рассмотреть первый случай, поскольку синтаксис более распространен.
источник
Пример копирования и вставки для переноса одной таблицы в другую с помощью MERGE:
Результат:
источник
Попробуй это,
источник
С http://www.praetoriate.com/oracle_tips_upserts.htm :
«В Oracle9i UPSERT может выполнить эту задачу в одном выражении:»
источник