Oracle SQL 多次插入忽略重复行

Posted

技术标签:

【中文标题】Oracle SQL 多次插入忽略重复行【英文标题】:Oracle SQL Multiple Insert Ignore duplicate rows 【发布时间】:2012-09-18 08:44:31 【问题描述】:

我想知道在 Oracle 中将多条记录复制到忽略某个索引上的重复值的数据库中的首选技术是什么。语句在语句中明确说明,而不是来自另一个表

INSERT INTO EXAMPLE (A, B, C, D) VALUES (null,'example1','example2',EXAMPLE_SEQ.nextval);
INSERT INTO EXAMPLE (A, B, C, D) VALUES (null,'example2','example3',EXAMPLE_SEQ.nextval);
INSERT INTO EXAMPLE (A, B, C, D) VALUES (null,'example4','example5',EXAMPLE_SEQ.nextval);

我目前正在这样做并手动检查,但需要找到一种方法以便将这些作为脚本处理

【问题讨论】:

您可以将它们作为脚本执行(SQL Developer 中的 F5,您在 Toad、Sql Navigator 等中有一个类似的按钮)。它只是记录一个错误并继续。 【参考方案1】:

如果您决定坚持使用INSERTs,则可以通过使用约束(无论是主键还是唯一键)来防止插入重复行。如果碰巧违反了唯一约束,您的脚本将停止,您将不得不回滚先前插入所做的所有更改(除非您已提交所有更改)。要处理该异常,您可以编写类似的 pls/sql 块。

declare
  l_unique_exception exception;
  pragma exception_init(l_unique_exception, -1);
begin
  insert into test(id, test_vector)
    values(1, 123);
  insert into test(id, test_vector)
   values(1, 123);
  ......
  Insert into 
  commit;
exception
  when l_unique_exception
    then process the exception;    
end;  

另外

如果您想在其中一个插入引发异常后继续,那么下面的示例可能会派上用场。

    创建一个包含错误的表。例如。

    CREATE TABLE tb_errors ( ErrorTag varchar2(123) )

    提供一个错误日志记录调用DBMS_ERRLOG 包的CREATE_ERROR_LOG 过程

    DBMS_ERRLOG.CREATE_ERROR_LOG('YourDmlTable. Test in this case', 'tb_errors');

    log errors into 子句添加到每个insert

这是一个例子

declare
begin
  insert into test(id, col1)
     values(1, 123)
     log errors into tb_errors('simple expression') reject limit unlimited;   
  insert into test(id, col1)
     values(1, 123)
     log errors into tb_errors('simple expression') reject limit unlimited;   
  insert into test(id, col1)
     values(1, 123) 
     log errors into tb_errors('simple expression') reject limit unlimited;
  commit;
end;

脚本完成后,您可以查询错误记录表,在这种情况下为tb_errors,以查看发生了什么问题。

【讨论】:

我正在使用这种技术,但我不明白您是如何捕获唯一键违规的,根据 11g 的 Oracle 文档,这似乎不是您可以捕获的错误 好的,我意识到你在这里所做的分配一个自定义错误,只要 ORA - 00001 被抛出。但是,这对我不起作用。我只是通过抛出 null 来处理它,但是脚本仍然失败并回滚。【参考方案2】:

您应该查看MERGE 语法。

http://en.wikipedia.org/wiki/Merge_(SQL)

merge example target
using (select 1 as id, 'a' as val) as source
    on source.id = target.id
    and source.val = target.val
when not matched then
    insert (id, val) values (source.id, source.val);

【讨论】:

我见过的所有合并示例都将一张表合并到另一张表中。我还没有看到在插入的脚本中明确声明值的示例。 我是否正确假设您必须为每个插入使用单独的合并块?对于相当基本的插入来说,这似乎是一大堆代码。 不 - 您可以将所有源数据放入源部分 @user898465:只需要一个合并语句。您可以将所有值放入using 部分:select 1 as id, 'a' as val from dual union all select 2, 'b' from dual union all ...【参考方案3】:

如果您的目标是对不正确的数据提供额外的处理,我建议您使用 LOG 错误子句。请考虑http://www.oracle-base.com/articles/10g/dml-error-logging-10gr2.php - 有很好的例子。

【讨论】:

以上是关于Oracle SQL 多次插入忽略重复行的主要内容,如果未能解决你的问题,请参考以下文章

忽略插入违反重复键索引的行

SQL:多次重复结果行,并对行进行编号

在将数据插入 Oracle 表时查找重复行

Oracle始终获取具有标识的插入行的ID [重复]

PL/SQl,oracle 9i,使用sql删除重复行

哪种 SQL 模式可以更快地避免插入重复行?