【问题标题】:ORA-38104: LHS of UPDATE SET contains the columns referenced in the ON ClauseORA-38104: UPDATE SET 的 LHS 包含 ON 子句中引用的列
【发布时间】:2018-02-10 13:09:11
【问题描述】:

我需要更新(D.SELLER_ACCOUNT_ID = S.ACCOUNT_ID AND D.CATEGORY_ID = S.CATEGORY_ID_OLD) 上的行。

如何在 Oracle 中更正以下查询?

MERGE INTO T_EVM_CLASSIFICATION D
   USING (SELECT CATEGORY_ID_NEW, CATEGORY_ID_OLD, ACCOUNT_ID FROM DATA_TEMP) S
   ON (D.SELLER_ACCOUNT_ID = S.ACCOUNT_ID AND D.CATEGORY_ID = S.CATEGORY_ID_OLD)
   WHEN MATCHED THEN UPDATE SET D.CATEGORY_ID = S.CATEGORY_ID_NEW;

【问题讨论】:

  • 您遇到的错误是什么
  • @Rams:错误就在这篇文章的标题中。

标签: sql oracle ora-38104


【解决方案1】:

There are a few possible workarounds which can be used to outsmart the parser,至少在 Oracle 18c 之前。其中之一是使用额外的虚拟列将谓词包装在行值表达式谓词中:

MERGE INTO T_EVM_CLASSIFICATION D
   USING (SELECT CATEGORY_ID_NEW, CATEGORY_ID_OLD, ACCOUNT_ID FROM DATA_TEMP) S
   ON (D.SELLER_ACCOUNT_ID = S.ACCOUNT_ID 
     AND (D.CATEGORY_ID, 'dummy') = ((S.CATEGORY_ID_OLD, 'dummy')))
   WHEN MATCHED THEN UPDATE SET D.CATEGORY_ID = S.CATEGORY_ID_NEW;

【讨论】:

    【解决方案2】:

    将“违规”条件从 ON 子句移至 WHERE 子句:

    MERGE INTO T_EVM_CLASSIFICATION D
       USING (SELECT CATEGORY_ID_NEW, CATEGORY_ID_OLD, ACCOUNT_ID FROM DATA_TEMP) S
       ON (D.SELLER_ACCOUNT_ID = S.ACCOUNT_ID)
       WHEN MATCHED THEN UPDATE SET   D.CATEGORY_ID = S.CATEGORY_ID_NEW
                                WHERE D.CATEGORY_ID = S.CATEGORY_ID_OLD;
    

    【讨论】:

    • 关于WHERE 子句,值得一提的是,它似乎并没有从BUNDLE_NAME 上的任何索引中获利,所以UPDATE 语句(或some other workarounds)肯定看起来更可取
    • @LukasEder - 什么是BUNDLE_NAME?我在MERGE 声明中的任何地方都没有看到它,所以我真的不知道你在说什么。如果你这样做,请解释一下。在任何情况下:请注意,在某些情况下MERGE 将起作用而UPDATE 将不起作用 - 例如,如果列 S.ACCOUNT_ID 中没有重复项,但该列未明确限制为 UNIQUE。跨度>
    • 抱歉,列名错误。我之前刚刚回答了另一个问题,以BUNDLE_NAME 为专栏。在这种情况下,它将是CATEGORY_ID
    【解决方案3】:

    如果存在 1:1 关系,请使用简单的update

    update t_evm_classification d set category_id = (
      select category_id_new 
        from data_temp s
        where d.seller_account_id = s.account_id 
          and d.category_id = s.category_id_old )
    

    如果临时表中的数据不存在,上述更新将使category_id 无效。为避免这种情况,请添加 where 子句:

    update t_evm_classification d 
      set category_id = ( select category_id_new 
                            from data_temp s
                           where d.seller_account_id = s.account_id 
                             and d.category_id = s.category_id_old )
      where (d.seller_account_id, d.category_id) in 
        (select s.account_id, category_id_old from data_temp s)
    

    【讨论】:

    • 非常感谢您的解决方案!这看起来很完美,但会抛出 ORA-01407: cannot update (%s) to NULL。我查了一下,data_temp 表中没有 NULL。我还尝试了没有更新的内部选择:select category_id_new from data_temp s, t_evm_classification d where d.seller_account_id = s.account_id and d.category_id = s.category_id_old,它返回了正确的数据。
    • @KonstantinFedosov - 如果目标表中的数据在源表中没有匹配项,则子查询将不返回任何行。如果子查询用作标量子查询(在这里,用于 UPDATE 语句中的赋值),则“无行”被视为 NULL,因此尝试将 category_id 更新为 NULL,对于 at目标表的至少一行。与原始 MERGE 语句中的解决方案一样(我在另一个答案中展示了如何解决该问题),是将 category_id_old 上的检查移至 WHERE 子句。
    • @KonstantinFedosov - 似乎category_id 不能为空。好的。我的update 的第二个版本,包含where,可以保护我们在这种情况下免于更新。唯一的另一个原因是data_temp.category_id_new 包含一些空值。无论如何@mathguy的解决方案应该更快,所以使用它。
    猜你喜欢
    • 2011-08-19
    • 2014-06-14
    • 1970-01-01
    • 2021-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-20
    • 2017-06-10
    相关资源
    最近更新 更多