我试图用一种复杂的源数据集更新表。有一个表格包含有关产品的库存信息。它还包含现场产品说明。该字段有时仍然有一些旧的描述,需要由基础数据表更新。
但是连接表也需要通过另一个子选择或连接完成的语言进行过滤。
SELECT products.DESCSH as old_desc
,parcel.DESCSH as new_desc
FROM parcel
,products
WHERE parcel.PRODU_INTERNUM = products.INTERNUM
AND parcel.NUM LIKE '2%REGEN'
and (SELECT COMPA.LANG FROM COMPA WHERE COMPA.NUM = parcel.COMPA_NUM) = products.LANG
and trim(upper(products.DESCSH)) <> trim(upper(parcel.DESCSH))
这是基础选择。 (该任务基本上是用old_desc更新new_desc)
既然我不知道如何做到这一点,我在这里看到了3种方法。 MERGE方法
merge into gc_prcel target
using (
Select p.descsh
,p.internum
from p
,par
where sysdate between p.vldty_beg and p.vldty_end
and p.internum = par.produ_internum
and p.lang = (SELECT COMPA.LANG FROM COMPA WHERE COMPA.NUM = par.COMPA_NUM)
) source
on (target.produ_internum = source.internum)
when matched then update
set target.descsh = source.descsh
where target.num like '2%REGENSDO'
and trim(upper(target.descsh)) <> trim(upper(target.descsh));
当它只更新400条记录时,这个要么更新几乎整个表格,而且我无能为力,或者它陷入无限循环(甚至更无能)。我知道这看起来很奇怪我为那些条款尝试了许多不同的地方,但没有一个工作。
使用EXIST子句的方法(我可以使用这个,但我发现其他方法更优雅),以及直接从子选择中更新字段的方法:
update
(SELECT products.DESCSH as old_desc
,parcel.DESCSH as new_desc
FROM parcel
,products
WHERE parcel.PRODU_INTERNUM = products.INTERNUM
AND parcel.NUM LIKE '2%REGENSDO'
and (SELECT COMPA.LANG FROM COMPA WHERE COMPA.NUM = parcel.COMPA_NUM) = products.LANG
and trim(upper(products.DESCSH)) <> trim(upper(parcel.DESCSH))) descriptions
set descriptions.new_desc = descriptions.old_desc;
这个抛出(ORA-01779:无法修改映射到非密钥保留表的列)
我是否尝试使用合并语句来完成任务,或者我是否必须使用存在的更新以及为什么我的第一种方法因ORA-01779而失败?
答案 0 :(得分:0)
你做的很聪明 - 在MERGE和UPDATE中 - 只有在值发生变化时才更新行。但在MERGE你写的这个 - 你能发现错误吗? (这可能是长时间执行的原因或原因之一。)
and trim(upper(target.descsh)) <> trim(upper(target.descsh));
好吧,这不应该是一个猜谜游戏;其中一个参数应为source.deschs
,双方都有target
。
编辑:或者实际上等待,这会导致语句不更新任何内容,因为该条件永远不会为TRUE。这是你用过的陈述吗? 结束修改
对于UPDATE和你得到的错误,我在Stack Overflow的“Documentation”域中写了这篇短文。它解释了您获得的错误以及如何解决它:Update with joins
答案 1 :(得分:0)
如果gc_prcel和par(我认为这实际上是你在更新语句中提到的parcel表?)是不同的表,那么我会进行合并,如:
merge into gc_prcel target
using (
Select p.descsh
,p.internum
from p
inner join par on p.internum = par.produ_internum
and trim(upper(p.descsh)) <> trim(upper(par.descsh)
where sysdate between p.vldty_beg and p.vldty_end
and p.lang = (SELECT COMPA.LANG FROM COMPA WHERE COMPA.NUM = par.COMPA_NUM)
and par.num like '2%REGENSDO');
) source
on (target.produ_internum = source.internum)
when matched then update
set target.descsh = source.descsh;
但是,如果这是您要更新的包裹表,我会选择以下内容:
merge into parcel tgt
using (select p.internum,
p.descsh,
compa.num
from products p
inner join compa on p.lang = compa.lang
where sysdate between p.vldty_beg and p.vldty_end) src
on (tgt.produ_internum = src.internum
and tgt.num like '2%REGENSDO'
and tgt.compa_num = src.compa_num)
when matched then
update set tgt.descsh = src.descsh
where trim(upper(tgt.descsh)) != trim(upper(src.descsh));