我在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"
我的要求是它第一次运行时应该插入,当我再次运行时它应该选择该记录并更新它。请在合并声明中告诉我要调整的内容,以便在此处按预期工作。提前谢谢。
答案 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次更改。
- 在'using'子查询里面'RRRR'正在myTable.myRef列中检查,但插入'myref1'的同时插入了它。因此,在使用子查询中更改了'myref1'。
- 'uuuu'已在同一张支票中介绍。
- DUAL tas在右外连接中引入。
醇>
查询将按以下方式处理 -
1.在第一次运行时,mytable中没有行。因此,具有双重权利的右外连接将占上风。这将使插入发生。
- 在第二次运行期间,将有一行myRef列为'myref1'。它的Rowid将被拾取并且更新将会发生。更新后,myRef列将更新为“uuuu”。
醇>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)
其中变量newID
,newTable_name
,newName
和newRef
来自您正在使用的任何数据源。
另外 - 你真的想要主键是(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');
第一次插入行时,对于后续运行,它将更新行。