Вставка Oracle SQL, если не существует

У меня есть таблица foo с ПК int id,varchar state

table foo:
- int id
- varchar state
- int code1
- int code2

Я хочу сделать вставку sql, если запись еще не существует.

Чтобы завершить оператор вставки, мне нужно получить некоторую информацию с помощью выбора вставки.

На входе у меня есть:

id = 1, state = 'A'

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

code1 and code2 where id = 1 (they are always the same for id = x)

Обычно я должен сделать:

1- выбор с where id=1 and state=1, и если он не существует, мне придется выполнить вставку sql

2- если запись не существует, получить значения полей code1 and code2 when id=1

3- сделать вставку

Можно ли сделать все в одном запросе?

select * from foo where id=1 and state = 'A'

если уже не существует:

select code1,code2 from foo where id=1; #1,2
insert into foo(id, state, code1, code2) values (1,'A', 1, 2);

можно ли объединить в один запрос?

Спасибо


person michele    schedule 19.02.2019    source источник
comment
Скорректировал ответ на основе вашего вопроса о движущейся цели;)   -  person Marmite Bomber    schedule 19.02.2019


Ответы (4)


Вы можете использовать insert . . . select:

insert into foo (id, some)
    select 1, 'text'
    from dual
    where not exists (select 1 from foo where id = 1);
person Gordon Linoff    schedule 19.02.2019

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

Но если вы «действительно» хотите проверить перед вставкой, вы можете попробовать блок PL/SQL.

PL/SQL

declare
  _id INTEGER
begin
  SELECT id into _id from foo;
exception
  when NO_DATA_FOUND then
    insert into foo(id,some) values (1,'text');
end;
/

ПРИМЕЧАНИЕ. Убедитесь, что у вас есть / в конце. Это запустит ваш блок PL/SQL.

В основном этот блок пытается выбрать строку с заданным id. Если существует, просто нормально завершает блок. Если строки не возвращаются, то это «исключение» для блока, и вы «обрабатываете» его, вставляя то, что вам нужно.

По-другому

begin
  insert into foo(id,some) values (1,'text');
exception
  when DUP_VAL_ON_INDEX then
    DBMS_OUTPUT.PUT_LINE('Already exists');
end;
/

ПРИМЕЧАНИЕ. Если вы хотите увидеть какие-либо выходные данные блока PL/SQL, вам может потребоваться выполнить set serveroutput on; перед запуском любого блока PL/SQL.

Надеюсь это поможет.

person Raihanul    schedule 19.02.2019

Вы можете использовать *волшебную подсказку Oracle IGNORE_ROW_ON_DUPKEY_INDEX для этой цели. Подсказка молча пропускает дублированную вставленную строку, что обычно вызывает `ORA-00001: уникальное ограничение (...) нарушено.

Я предполагаю следующую настройку таблицы:

create table foo
(id number not null,
 status varchar2(1) not NULL,
 code1 varchar2(10),
 code2 varchar2(10));

alter table foo add (primary key (id, status)); 

insert into foo (id,status, code1,code2) values(1,'a','xxx', 'xxx');
insert into foo (id,status, code1,code2) values(1,'b','xxx', 'xxx');

insert into foo (id,status, code1,code2) values(2,'b','yyy', 'yyy');
commit;

Итак, теперь вы хотите проигнорировать вставку с ключом 1 и выполнить вставку с ключом 2, используя code из записи со статусом 'b'.

Это должно дать вам представление о том, как действовать дальше:

insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX (foo (id, status)) */ into foo (id,status, code1,code2) 
values( 1, 'a', 
(select code1 from foo where id = 1 and status = 'b'),
(select code2 from foo where id = 1 and status = 'b'));

0 rows created.

insert /*+ IGNORE_ROW_ON_DUPKEY_INDEX (foo (id, status)) */ into foo (id,status, code1,code2) 
values( 2, 'a', 
(select code1 from foo where id = 2 and status = 'b'),
(select code2 from foo where id = 2 and status = 'b'));

1 rows created.

Настройте подзапрос, чтобы получить code1 и code2 по мере необходимости - вы можете использовать max(code1) и игнорировать status.

Используйте переменную связывания, чтобы передать id (три раза) в запросе.

person Marmite Bomber    schedule 19.02.2019

В Oracle это можно сделать с помощью одного оператора: >используйте оператор MERGE. В вашем случае вы бы сделали что-то вроде:

MERGE INTO FOO
  USING (SELECT f.ID,
                'A' AS STATE,
                f.CODE1,
                f.CODE2
           FROM FOO f
           WHERE f.ID = 1) d
    ON (d.ID = FOO.ID AND
        d.STATE = FOO.STATE)
  WHEN NOT MATCHED THEN INSERT
    (ID, STATE, CODE1, CODE2)
  VALUES
    (d.ID, d.STATE, d.CODE1, d.CODE2)

Удачи.

person Bob Jarvis - Reinstate Monica    schedule 19.02.2019