【发布时间】:2023-03-16 01:13:01
【问题描述】:
我需要在 Oracle 中同步两个表。我使用 MERGE 来完成这项工作,但我需要帮助才能获得有效的 SQL 来完成这项工作。
我的目标表有一个 PK 和一些其他列。其中一些列没有空约束。
我的源表的布局和数据与我的目标表不同,所以我需要查询我的源表并将数据转换为目标布局。
我的实际代码是(简化的):
MERGE INTO TARGET t USING(
WITH SRC AS ( --do the transformation
SELECT ID, DECODE(VAL,'THIS','THAT','OTHER') VAL1, REGEXP_SUBSTR(VAL,'\d+') VAL2 FROM SOURCE
)
SELECT t.ROWID ROW_ID, s.* FROM SRC s
FULL OUTER JOIN TARGET t ON s.ID=t.ID
) s ON (t.ROWID=s.ROW_ID)
WHEN MATCHED THEN UPDATE SET t.VAL1=s.VAL1 AND t.VAL2=s.VAL2
DELETE WHERE s.ID IS NULL
WHEN NOT MATCHED THEN INSERT(ID, VAL1, VAL2) VALUES (s.ID, s.VAL1, s.VAL2);
问题在于,这些符合 DELETE 条件的行会抛出 ORA-01407: cannot update (string) to NULL。看来,Oracle 首先尝试更新并稍后执行删除。这会导致错误。
MERGE 关键字对于同步删除表来说真的很糟糕,但我想使用单个查询,因为我的转换 SQL 真的很重。
是否有任何替代 MERGE 的方法或任何建议以使其正常工作?
谢谢
这就是我的解决方案。也许这可以帮助某人。
MERGE INTO TARGET t USING(
WITH SRC AS ( --do the transformation
SELECT ID, DECODE(VAL,'THIS','THAT','OTHER') VAL1, REGEXP_SUBSTR(VAL,'\d+') VAL2 FROM SOURCE
)
SELECT t.ROWID ROW_ID, NVL2(s.ID,null,1) delFlag, s.*
FROM SRC s
FULL OUTER JOIN TARGET t ON s.ID=t.ID
) s ON (t.ROWID=s.ROW_ID)
WHEN MATCHED THEN UPDATE SET t.VAL1=NVL2(s.delFlag,t.VAL1,s.VAL1) AND t.VAL2=NVL2(s.delFlag,t.VAL1,s.VAL2)
DELETE WHERE s.delFlag IS NOT NULL
WHEN NOT MATCHED THEN INSERT(ID, VAL1, VAL2) VALUES (s.ID, s.VAL1, s.VAL2);
但是很奇怪,要删除的行必须通过约束检查。
【问题讨论】:
-
(当你提问出现错误时,请提供整个错误信息,而不仅仅是错误代码。我不了解你,但我不是甲骨文的行走百科全书错误代码!我已编辑您的问题以包含通用错误文本)
-
查询正常,错误出现在那些应该被删除的行上。我想知道为什么要对那些将被删除的人进行 NOTNULL 检查。
-
@NicoRichter - 因为更新是先完成的,所以必须满足约束;然后删除子句 (a sub-clause of update 应用于该更新的结果。“受此子句影响的唯一行是目标表中由合并操作更新的行。
DELETE WHERE条件评估更新的值,而不是原始值...”。在进行非空检查时,Oracle 不知道/不关心它们将被删除。