【问题标题】:Oracle SQL insert if not existOracle SQL 插入(如果不存在)
【发布时间】:2019-07-13 06:08:04
【问题描述】:

我有桌 foo 和 PK 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);

是否可以合并到一个查询中?

谢谢

【问题讨论】:

  • 根据你的移动目标问题调整了答案;)

标签: sql oracle select insert insert-select


【解决方案1】:

你可以使用insert . . . select:

insert into foo (id, some)
    select 1, 'text'
    from dual
    where not exists (select 1 from foo where id = 1);

【讨论】:

    【解决方案2】:

    在您的表中,id 是主键。因此,如果您尝试插入包含现有id 的行,oracle 将引发错误。 您可以随意处理该错误。

    但如果你“真的”想在插入前检查,你可以试试 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 块之前。

    希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      您可以为此目的使用 *magical Oracle 提示 IGNORE_ROW_ON_DUPKEY_INDEX。提示会默默地跳过重复的插入行 - 通常会导致 `ORA-00001: unique constraint (...) denied.

      我假设以下表格设置:

      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 的插入,并使用状态为'b' 的记录中的codes 执行键为2 的插入

      这应该让您知道如何进行:

      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.
      

      根据需要调整子查询以获取code1code2 - 您可以使用max(code1) 并忽略status

      使用绑定变量在查询中传递id(三次)。

      【讨论】:

        【解决方案4】:

        在 Oracle 的单个语句中执行此操作的方法是 use the MERGE statement。在您的情况下,您会执行以下操作:

        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)
        

        祝你好运。

        【讨论】:

          猜你喜欢
          • 2011-03-10
          • 2010-12-14
          • 1970-01-01
          • 2018-09-17
          • 2020-02-04
          • 2011-04-19
          • 1970-01-01
          • 2014-01-25
          相关资源
          最近更新 更多