使用复杂联接进行更新

时间:2017-02-02 14:33:53

标签: sql oracle merge

我试图用一种复杂的源数据集更新表。有一个表格包含有关产品的库存信息。它还包含现场产品说明。该字段有时仍然有一些旧的描述,需要由基础数据表更新。

但是连接表也需要通过另一个子选择或连接完成的语言进行过滤。

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而失败?

2 个答案:

答案 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));