更新连接中使用的列
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)
);
干杯!!
【讨论】:
以上是关于更新连接中使用的列的主要内容,如果未能解决你的问题,请参考以下文章