Подтвердить что ты не робот

Oracle sql: обновить, если существует else insert

Возможный дубликат:
Oracle: как UPSERT (обновить или вставить в таблицу?)

Привет,

У меня есть таблица, в которой запись должна быть изменена, если она уже существует иначе, чтобы новая запись была вставлена. Oracle sql не принимает IF EXISTS, иначе я бы сделал запрос if - update - else - insert. Я посмотрел на MERGE, но он работает только для нескольких таблиц. Что я делаю?

4b9b3361

Ответ 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), а затем решив, нужно ли вставлять или обновлять.