更新连接中使用的列

Posted

技术标签:

【中文标题】更新连接中使用的列【英文标题】:Update of column used in the join 【发布时间】:2019-07-30 13:24:20 【问题描述】:

我有一个表格,其中一列 (TXN_AMT) 填充不正确。我正在尝试使用来自同一个表的聚合数据更新该列,基于以下条件:对于给定日期的同一帐号,如果有多个交易并且交易金额大于或等于实际金额的总和,则更新交易金额与实际金额。我尝试使用MERGE 和子查询,但Oracle 拒绝了我的更新,并显示“无法更新ON 子句中引用的列”。我的查询:

MERGE INTO TXN W
USING (
  select TXN_AMT, ACCOUNT_NUM, TXN_DATE, sum(ACTUAL_AMT), count(1) 
  from TXN 
  where TXN_AMT is NOT NULL 
    and TXN_AMT > ACTUAL_AMT
  group by TXN_AMT, ACCOUNT_NUM, TXN_DATE
  having count(1) > 1 and TXN_AMT >= sum(ACTUAL_AMT)
) TBL
ON (W.ACCOUNT_NUM = TBL.ACCOUNT_NUM
  AND W.TXN_DATE = TBL.TXN_DATE
  AND W.TXN_AMT = TBL.TXN_AMT)
WHEN MATCHED THEN UPDATE SET W.TXN_AMT = W.ACTUAL_AMT;

我尝试为内部子查询创建一个单独的表,但这次 Oracle 以“无法在源表中获得一组稳定的行”拒绝了它。

我怎样才能做到这一点?

【问题讨论】:

错误清楚地表明当您在ON 子句中使用此列时,您无法更新列 W.TXN_AMT。请从 on 子句中删除此列并尝试一下。 我知道。但我需要考虑查询中的 TXN_AMT 我不确定我是否遵循您尝试执行的更新的逻辑,也不确定受影响表结构的相关部分。你能举个例子吗?你的表是如何键控的? 【参考方案1】:

您也可以在 MERGE 语句中执行此操作,方法是使用连接和分析函数中的 rowid 进行求和和计数,例如:

MERGE INTO txn w
USING (SELECT ROWID rid,
              txn_amt,
              account_num,
              txn_date,
              SUM(actual_amt) over(PARTITION BY txn_amt, account_num, txn_date) actual_amt,
              COUNT(1) over(PARTITION BY txn_amt, account_num, txn_date) actual_amt cnt
       FROM   txn
       WHERE  txn_amt IS NOT NULL
       AND    txn_amt > actual_amt) tbl
ON (w.rowid = tbl.rid AND tbl.cnt > 1)
WHEN MATCHED THEN
  UPDATE
  SET    w.txn_amt = w.actual_amt
  where  tbl.txn_amt >= tbl.actual_amt;

【讨论】:

当然这假设 (TXN_AMT, ACCOUNT_NUM, TXN_DATE) 是候选键。这似乎很可能基于 OP 的查询,但从问题中并不完全清楚。但是,如果这成立,那么这是一个不错的解决方案。 我收到错误 ORA-38104:无法更新 ON 子句中引用的列: @Sid 我已将问题连接条件移至更新部分的 where 子句。现在应该可以了。【参考方案2】:

将光标移到数据上并循环执行更新:

BEGIN
  FOR aRow IN (select TXN_AMT, ACCOUNT_NUM, TXN_DATE, sum(ACTUAL_AMT), count(1) 
                 from TXN 
                 where TXN_AMT is NOT NULL 
                   and TXN_AMT > ACTUAL_AMT
                 group by TXN_AMT, ACCOUNT_NUM, TXN_DATE
                 having count(1) > 1 and
                        TXN_AMT >= sum(ACTUAL_AMT))
  LOOP
    UPDATE TXN w
      SET TXN_AMT = aRow.ACTUAL_AMT
      WHERE w.ACCOUNT_NUM = aRow.ACCOUNT_NUM AND
            w.TXN_DATE = aRow.TXN_DATE AND
            w.TXN_AMT = aRow.TXN_AMT;
  END LOOP;
END;

【讨论】:

谢谢。因为,它是一个数据补丁 PL/SQL 块是不允许的【参考方案3】:

你可以试试下面的Update语句:

UPDATE TXN W
SET
    W.TXN_AMT = W.ACTUAL_AMT
WHERE
    ( W.TXN_AMT,
      W.ACCOUNT_NUM,
      W.TXN_DATE ) IN (
        SELECT
            TBL.TXN_AMT,
            TBL.ACCOUNT_NUM,
            TBL.TXN_DATE
        FROM
            TXN TBL
        WHERE
            TBL.TXN_AMT IS NOT NULL
            AND TBL.TXN_AMT > ACTUAL_AMT
        GROUP BY
            TBL.TXN_AMT,
            TBL.ACCOUNT_NUM,
            TBL.TXN_DATE
        HAVING COUNT(1) > 1
               AND TBL.TXN_AMT >= SUM(TBL.ACTUAL_AMT)
    );

干杯!!

【讨论】:

以上是关于更新连接中使用的列的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 DB2 中表的列值更新 DB1 中表的列值?

如何使用不相关表中的列数据更新列 - MySQL

如何使用内部连接更新行

使用 plpgsql 更新函数中的列

如何使用数组值更新数据库中的列?

仅在 1 个基表中更新数据库联接视图