在 Oracle 中,只有当 Oracle 能够为子查询的每一行准确定位基表中的一行且仅一行时,您才能更新子查询。此外,对分析功能、聚合等的使用还有其他限制。
在您的示例中,这DISTINCT
将使 Oracle 无法更新子查询,因为子查询的一行可能指向基表的几行。
如果删除DISTINCT
,则查询仅在存在唯一索引时才有效MATERIAL(item_id)
,因此表中的每一行POLINE
最多只能与 中的一行相关联MATERIAL
:
UPDATE (SELECT a.item_id, a.account_code acct_a,
b.item_id, b.account_code acct_b
FROM bp.poline a, mt.material b
WHERE a.item_id = b.item_id
AND a.account_code IS NOT NULL
AND b.account_code IS NULL)
SET acct_a = acct_b
更新一个连接是非常有效的,但是有几个限制,如果你没有这个索引怎么办?
您可以使用不同的子查询编写标准更新:
UPDATE poline a
SET a.account_code = (SELECT b.account_code
FROM material b
WHERE b.item_id = a.item_id
AND b.account_code is not null)
WHERE a.account_code IS NULL
AND a.item_id IN (SELECT b.item_id
FROM material b
WHERE b.account_code IS NOT NULL)
然而,受类似问题的回答启发,IMO 最优雅的解决方案是:
MERGE INTO (SELECT * FROM a WHERE account_code IS NULL) a
USING (SELECT * FROM b WHERE account_code IS NOT NULL) b
ON (a.item_id = b.item_id)
WHEN MATCHED THEN UPDATE SET a.account_code = b.account_code;