Oracle sql: обновить, если существует else insert
Возможный дубликат:
Oracle: как UPSERT (обновить или вставить в таблицу?)
Привет,
У меня есть таблица, в которой запись должна быть изменена, если она уже существует иначе, чтобы новая запись была вставлена.
Oracle sql не принимает IF EXISTS
, иначе я бы сделал запрос if - update - else - insert
. Я посмотрел на MERGE
, но он работает только для нескольких таблиц. Что я делаю?
Ответы
Ответ 1
Для MERGE не требуется "несколько таблиц", но для этого нужен запрос в качестве источника. Что-то вроде этого должно работать:
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);
В качестве альтернативы вы можете сделать это в PL/SQL:
BEGIN
INSERT INTO mytable (id, name) VALUES (1, 'x');
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
UPDATE mytable
SET name = 'x'
WHERE id = 1;
END;
Ответ 2
merge into MY_TABLE tgt
using (select [expressions]
from dual ) src
on (src.key_condition = tgt.key_condition)
when matched then
update tgt
set tgt.column1 = src.column1 [,...]
when not matched then
insert into tgt
([list of columns])
values
(src.column1 [,...]);
Ответ 3
Как я всегда это делаю (предполагая, что данные никогда не должны быть удалены, только вставлены) - это
- Сначала выполните
insert
, если это не удается с уникальным нарушением ограничения, вы знаете, что строка существует,
- Затем выполните
update
К сожалению, многие фреймворки, такие как Hibernate, обрабатывают все ошибки базы данных (например, уникальное нарушение ограничений) как неустранимые условия, поэтому это не всегда легко. (В Hibernate решение состоит в том, чтобы открыть новый сеанс/транзакцию только для выполнения этой команды insert
.)
Вы не можете просто сделать select count(*) .. where ..
, даже если это возвращает ноль, и поэтому вы выбираете insert
, между тем, как вы выполняете select
и insert
, у кого-то еще может быть insert
отредактируйте строку, и поэтому ваш insert
завершится с ошибкой.
Ответ 4
Вы можете использовать переменную Oracle SQL%ROWCOUNT
:
UPDATE table1
SET field2 = value2,
field3 = value3
WHERE field1 = value1;
IF (SQL%ROWCOUNT = 0) THEN
INSERT INTO table (field1, field2, field3)
VALUES (value1, value2, value3);
END IF;
Было бы проще просто определить, имеет ли ваш первичный ключ (т.е. field1
) значение, а затем выполняет соответственно вставку или обновление. То есть, если вы используете указанные значения в качестве параметров хранимой процедуры.
Ответ 5
HC-way:)
DECLARE
rt_mytable mytable%ROWTYPE;
CURSOR update_mytable_cursor(p_rt_mytable IN mytable%ROWTYPE) IS
SELECT *
FROM mytable
WHERE ID = p_rt_mytable.ID
FOR UPDATE;
BEGIN
rt_mytable.ID := 1;
rt_mytable.NAME := 'x';
INSERT INTO mytable VALUES (rt_mytable);
EXCEPTION WHEN DUP_VAL_ON_INDEX THEN
<<update_mytable>>
FOR i IN update_mytable_cursor(rt_mytable) LOOP
UPDATE mytable SET
NAME = p_rt_mytable.NAME
WHERE CURRENT OF update_mytable_cursor;
END LOOP update_mytable;
END;
Ответ 6
Пожалуйста, обратитесь к этому вопросу, если вы хотите использовать команду UPSERT/MERGE в Oracle. В противном случае просто разрешите проблему на стороне клиента, сначала сделав count(1)
, а затем решив, нужно ли вставлять или обновлять.