plsql:从选择中插入多行并忽略重复项

Posted

技术标签:

【中文标题】plsql:从选择中插入多行并忽略重复项【英文标题】:plsql: inserting Multiple rows from select and ignore duplicates 【发布时间】:2014-12-26 14:25:40 【问题描述】:

我正在使用带有 TOAD 的 oracle 10g。 我需要使用 INSERT FROM SELECT 插入 lacs 记录。

BEGIN    
    INSERT INTO MYTABLE(C1,C2,C3)  
    SELECT C1,C2,C3 FROM MYTABLE2 WHERE C1>100;
EXCEPTION    
         WHEN DUP_VAL_ON_INDEX  THEN NULL;    
COMMIT;    
END;

这里,我面临的问题是,如果这个选择查询返回的行已经存在于 MYTABLE 中,那么所有事务都将被回滚。

有没有办法插入所有不存在的行,忽略重复的行并继续插入不存在的行,然后提交事务?

【问题讨论】:

只需选择不同的 c1,c2,c3 ... where not exists (select 1 from mytable mt where mt.c1 = mytable.c1 and mt.c2 = mytable.c2 and mt.c3 = mytable.c3) 嗨,迈克,选择查询从多个表中获取列。三列来自三个不同的表。 你在编辑方面打败了我。您可能也可以进行合并,但正如您所见,有很多方法可以做到这一点。不匹配时使用 mytable2 m2 在 (m1.c1 = m2.c1 and m1.c2 = m2.c2 and m1.c3 = m2.c3) 上合并到 mytable m1,然后插入值 (m2.c1, m2.c2, m2. c3); 【参考方案1】:

使用独特的关键字

开始 插入 MYTABLE(C1,C2,C3) 从 MYTABLE2 中选择不同的 C1、C2、C3,其中 C1>100; 例外 当 DUP_VAL_ON_INDEX 为空时; 提交; 结束;

【讨论】:

您好 Sandeep,选择查询从多个表中获取列。三列来自三个不同的表 您好 User1583751,即使 select 查询从多个表中获取记录,distinct 关键字也会删除 C1、C2、C3 的所有重复条目,然后将记录插入到 MYTABLE 中 distinct 在使用多个表时失败。 Select 可能会给我来自 table2 的不同记录,但是在插入 table1 时,它不会识别 table1 中的不同记录。 select 和 distinct 位于 x 表中,而插入位于 y 表中。 :) 您可以按照 Mike 的建议使用 Merge 语句,能否请您在此处粘贴您正在使用的确切 SQL 查询。【参考方案2】:

您可以首先避免这些行,而不是尝试处理异常,例如,通过使用 minus 运算符:

INSERT INTO mytable (c1, c2, c3)  
SELECT c1, c2, c3 
FROM   mytable2 
WHERE  c1 > 100;
MINUS
SELECT c1, c2, c3
FROM   mytable
WHERE  c1 > 100 -- not necessary, but should improve performance

【讨论】:

嗨 Mureinik,我需要知道我在异常部分跳过了哪些行。然后继续其他记录。但我的问题是,一旦引发异常,整个交易就会被抛售。【参考方案3】:

有很多方法可以做到这一点。首先,你可以试试这样:

insert into mytable(c1, c2, c3)
select distinct c1, c2, c3 from mytable2 where c1 > 100
minus
select c1, c2, c3 from mytable;

否则,你可以使用类似的东西

insert into mytable(c1, c2, c3)
select c1, c2, c3 from mytable2 where c1 > 100
log errors into myerrtable reject limit unlimited;

等等……

有关错误记录的更多详细信息。自 10g 第 2 版以来引入的功能。

SQL> create table garbage(id integer);

Table created

SQL> insert into garbage select rownum from dual connect by level <= 10;

10 rows inserted

SQL> insert into garbage values (3);

1 row inserted

SQL> insert into garbage values (5);

1 row inserted

SQL> create table uniq(id integer not null primary key);

Table created

SQL> insert into uniq select * from garbage;

ORA-00001: unique constraint (TEST.SYS_C0010568) violated

SQL> select count(*) from uniq;

  COUNT(*)
----------
         0

SQL> exec dbms_errlog.create_error_log('uniq', 'uniq_err');

PL/SQL procedure successfully completed

SQL> insert into uniq select * from garbage
  2  log errors into uniq_err reject limit unlimited;

10 rows inserted

SQL> select * from uniq;

                                     ID
---------------------------------------
                                      1
                                      2
                                      3
                                      4
                                      5
                                      6
                                      7
                                      8
                                      9
                                     10

10 rows selected

SQL> select ora_err_mesg$, id from uniq_err;

ORA_ERR_MESG$                                                          ID
---------------------------------------------------------------------- --
ORA-00001: unique constraint (TEST.SYS_C0010568) violated              3
ORA-00001: unique constraint (TEST.SYS_C0010568) violated              5

【讨论】:

我收到您的最后一行错误“将错误记录到 myerrtable 拒绝限制无限制;” [错误] 执行 (49: 5):ORA-06550:第 13 行,第 5 列:PLS-00103:在预期以下情况之一时遇到符号“错误”::=。 (@%;【参考方案4】:

我以为我会回答这个问题,但这实际上取决于您要达到的目标。

您可以使用以下方法检查数据是否已在 table2 中:

INSERT INTO mytable2 (c1, c2, c3) 
SELECT DISTINCT c1,c2,c3 FROM mytable t1
WHERE c1 > 100 
AND NOT EXISTS 
(select 1 from mytable2 t2 where t2.c1 = t1.c1 and t2.c2 = t1.c2 and t2.c3 = t1.c3);

或者你可以使用这样的合并:

MERGE INTO mytable2 m2
USING (SELECT DISTINCT c1, c2, c3 FROM mytable) m1 
ON (m1.c1 = m2.c1 and m1.c2 = m2.c2 and m1.c3 = m2.c3) 
WHEN NOT MATCHED THEN INSERT (c1, c2, c3)  VALUES (m1.c1, m1.c2, m1.c3)
where m1.c1 > 100;

在这两个示例中,您只会将唯一行插入到 mytable2 中

【讨论】:

以上是关于plsql:从选择中插入多行并忽略重复项的主要内容,如果未能解决你的问题,请参考以下文章

如何忽略MySQL中insert语句的连续重复

选择所有但忽略重复项[重复]

django批量创建忽略重复项[重复]

如何在 9.414 版本中使用 executemany 忽略 postgres 中的重复项?

如何遍历列表并检索最小值的索引但忽略输出列表中的重复项?

Oracle中的多行插入查询(从一张表中选择多行并插入到另一张表中[重复]