Oracle Merge语句未插入数据

时间:2016-09-10 09:18:55

标签: sql oracle oracle11g merge

我在oracle 11g上提出了下面的sql语句来合并数据。

  MERGE INTO myTable tgt
USING ( SELECT myTable.ROWID AS rid
         FROM   myTable

        WHERE myTable.myRef = 'uuuu' or
        myTable.name = 'sam'
        --union
        --select rowId,null from dual
      ) src
ON (tgt.rowid = src.rid)
WHEN MATCHED THEN
update set tgt.myRef = 'uuuu',tgt.name='name_worked'
when not matched then 
insert (
tgt.myRef,tgt.name) values ('RRRR','HHH');

我需要在此处插入ID列以外的数据,这些数据将从主键插入的触发器进行管理。由于错误ORA-38104: Columns referenced in the ON Clause cannot be updated我在这里使用了RowId方法。

现在我的问题是merge语句在更新时工作正常,但在这种情况下插入数据失败。

我浏览了这个post并添加了union语句。但由于我的表格中的约束而不是顺利运行,因此在插入重复记录时仍然失败。

有人可以帮帮我吗?欣赏它很多。先谢谢你。

==========被修改===========

请在下面找到完整的代码示例和错误消息。

MERGE INTO myTable tgt
USING ( SELECT myTable.ROWID AS rid
         FROM   myTable

        WHERE myTable.myRef = 'RRRR' or
        myTable.mytablename = 'sam'
        union
        select rowId from dual
      ) src
ON (tgt.rowid = src.rid)
WHEN MATCHED THEN
update set tgt.myRef = 'uuuu',tgt.mytablename='myt_name', tgt.name='nameA'
when not matched then 
insert (
tgt.mytableid,tgt.mytablename,tgt.name,tgt.myRef) values (11,'RRRR','HHH','myref1');

我的桌子是 -

CREATE TABLE "sa"."MYTABLE"
  (
    "MYTABLEID"   NUMBER NOT NULL ENABLE,
    "MYTABLENAME" VARCHAR2(20 BYTE) NOT NULL ENABLE,
    "NAME"        VARCHAR2(20 BYTE),
    "MYREF"       VARCHAR2(20 BYTE),
    CONSTRAINT "MYTABLE_PK" PRIMARY KEY ("MYTABLEID", "MYTABLENAME")
  )

如果我第一次运行它将按预期插入记录。 当我第二次运行它时,我的期望是它应该匹配myRef = 'RRRR'并进行更新。我故意把'或'放在条件之间,因为如果我发现表中存在任何值,它应该去更新现有记录。

但是它不会执行该更新,而是会抛出此错误,因为merge语句会再次尝试插入。

SQL Error: ORA-00001: unique constraint (sa.MYTABLE_PK) violated
00001. 00000 -  "unique constraint (%s.%s) violated"

我的要求是它第一次运行时应该插入,当我再次运行时它应该选择该记录并更新它。请在合并声明中告诉我要调整的内容,以便在此处按预期工作。提前谢谢。

3 个答案:

答案 0 :(得分:2)

以下MERGE查询是您正在寻找的。

MERGE INTO myTable tgt
USING ( select x.rid from 
       (SELECT myTable.ROWID AS rid
        FROM   myTable 
        WHERE myTable.myRef IN ('myref1','uuuu')) x 
        right outer join dual 
        on x.rowid <> dual.rowid
      ) src
ON (tgt.rowid = src.rid)
WHEN MATCHED THEN
update set tgt.myRef = 'uuuu',tgt.mytablename='myt_name', tgt.name='nameA'
when not matched then 
insert (tgt.mytableid,tgt.mytablename,tgt.name,tgt.myRef) values (mytable_seq.nextval,'RRRR','HHH','myref1');

您提供的查询已进行了3次更改。

  
    
        
  1. 在'using'子查询里面'RRRR'正在myTable.myRef列中检查,但插入'myref1'的同时插入了它。因此,在使用子查询中更改了'myref1'。
  2.     
  3. 'uuuu'已在同一张支票中介绍。
  4.     
  5. DUAL tas在右外连接中引入。
  6.        

查询将按以下方式处理 -

  
    

1.在第一次运行时,mytable中没有行。因此,具有双重权利的右外连接将占上风。这将使插入发生。

         
        
  1. 在第二次运行期间,将有一行myRef列为'myref1'。它的Rowid将被拾取并且更新将会发生。更新后,myRef列将更新为“uuuu”。
  2.               

    3.在所有后续运行中,使用子查询总是在内部返回1行,这次是因为'uuuu'的列值。这将使更新发生,这将再次使用相同的现有值更新列。

      

因此实际上,第一次INSERT将发生,并且在随后的所有时间都会发生UPDATE。

答案 1 :(得分:1)

您似乎想要以下内容:

MERGE INTO MYTABLE t
  USING (SELECT newID, newTable_name from DUAL) d
    ON (t.MYTABLEID = d.newID AND
        t.MYTABLENAME = d.newTable_name)
  WHEN MATCHED THEN
    UPDATE SET NAME = newName,
               MYREF = newRef
  WHEN NOT MATCHED THEN
    INSERT (MYTABLEID, MYTABLENAME, NAME, MYREF)
    VALUES (newID, newTable_name, newName, newRef)

其中变量newIDnewTable_namenewNamenewRef来自您正在使用的任何数据源。

另外 - 你真的想要主键是(MYTABLEID,MYTABLENAME)吗?你真的可以有多个具有相同MYTABLEID值的行吗?你真的想要允许多行具有相同的MYTABLENAME值吗?我的想法是主键应该是MYTABLEID,对MYTABLENAME有一个UNIQUE约束。如果是这种情况,那么MYTABLEID是多余的,MYTABLENAME可以用作主键。 ????

祝你好运。

答案 2 :(得分:0)

我能够在下面的查询中完成这项工作。

MERGE INTO myTable tgt
USING ( SELECT (SELECT myTable.ROWID AS rid 
         FROM   myTable

        WHERE myTable.myRef = '2' or
        myTable.mytablename = 'sam'
      ) as rid from dual)  src
ON (tgt.rowid = src.rid)
WHEN MATCHED THEN
update set tgt.myRef = 'uuuu',tgt.mytablename='test1', tgt.name='nameA'
when not matched then 
insert (
tgt.mytableid,tgt.mytablename,tgt.name,tgt.myRef) values (11,'RRRR1','1','2');

第一次插入行时,对于后续运行,它将更新行。