You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Oracle 12C 2.2执行并行DML Merge查询时遭遇ORA-12801与ORA-30926错误求助

解决ORA-30926与ORA-12801的Merge语句报错问题

咱们先把错误根源说清楚:

  • ORA-30926:这是核心问题——你的源表EDWFIN.PSP_LABOR_SCHD_DAY_F_ROLLUP_FRS_356(简称B)里,存在多条记录匹配目标表A的同一行。具体来说,PAY_RANGE_START_DATE_KEY + AA_PERSON_NATURAL_KEY + AA_PERSON_ASSIGNMENT_KEY这个组合在B表中有重复值,Merge操作要求源表对目标表的每一行只能有唯一匹配项,否则数据库不知道该用哪条源记录更新目标行,直接抛出这个错误。
  • ORA-12801:这是并行查询服务器触发的衍生错误,本质是并行执行时放大了前面的重复匹配问题,只要解决了源表的重复问题,这个错误自然会消失。

下面给你几个可行的解决办法,按优先级排序:

1. 清理源表B的重复数据(最彻底方案)

如果业务逻辑上B表不应该存在上述组合的重复记录,先做去重处理:

-- 第一步:先排查重复的记录
SELECT PAY_RANGE_START_DATE_KEY, AA_PERSON_NATURAL_KEY, AA_PERSON_ASSIGNMENT_KEY, COUNT(*) AS duplicate_count
FROM EDWFIN.PSP_LABOR_SCHD_DAY_F_ROLLUP_FRS_356
GROUP BY PAY_RANGE_START_DATE_KEY, AA_PERSON_NATURAL_KEY, AA_PERSON_ASSIGNMENT_KEY
HAVING COUNT(*) > 1;

-- 第二步:保留最新的一条(按SRC_LAST_UPDATE_DATE取最大),删除重复项
DELETE FROM EDWFIN.PSP_LABOR_SCHD_DAY_F_ROLLUP_FRS_356 B
WHERE ROWID NOT IN (
    SELECT MAX(ROWID)
    FROM EDWFIN.PSP_LABOR_SCHD_DAY_F_ROLLUP_FRS_356
    GROUP BY PAY_RANGE_START_DATE_KEY, AA_PERSON_NATURAL_KEY, AA_PERSON_ASSIGNMENT_KEY
);
COMMIT;

清理完成后再执行原Merge语句,就能正常运行了。

2. 在Merge的USING子句中临时去重(无需修改源表)

如果不能直接修改源表B,那就在Merge的源数据部分先做去重处理,确保每个匹配组合只有一条记录。比如取更新日期最新的那条:

ALTER session enable parallel dml;
MERGE /*+ parallel(A) enable_parallel_dml*/ INTO EDWFIN.PSP_LABOR_SCHD_DAY_F_ROLLUP A
USING (
    -- 先对B表做去重,每个组合只保留最新更新的记录
    SELECT PAY_RANGE_START_DATE_KEY, AA_PERSON_NATURAL_KEY, AA_PERSON_ASSIGNMENT_KEY,
           SRC_CREATED_DATE, SRC_LAST_UPDATE_DATE
    FROM (
        SELECT B.*,
               ROW_NUMBER() OVER (
                   PARTITION BY PAY_RANGE_START_DATE_KEY, AA_PERSON_NATURAL_KEY, AA_PERSON_ASSIGNMENT_KEY
                   ORDER BY SRC_LAST_UPDATE_DATE DESC
               ) AS rn
        FROM EDWFIN.PSP_LABOR_SCHD_DAY_F_ROLLUP_FRS_356 B
    )
    WHERE rn = 1
) B
ON ( A.PAY_RANGE_START_DATE_KEY = B.PAY_RANGE_START_DATE_KEY
AND A.AA_PERSON_NATURAL_KEY = B.AA_PERSON_NATURAL_KEY
AND A.AA_PERSON_ASSIGNMENT_KEY = B.AA_PERSON_ASSIGNMENT_KEY )
WHEN MATCHED THEN UPDATE
SET A.SRC_CREATED_DATE = B.SRC_CREATED_DATE,
A.SRC_LAST_UPDATE_DATE = B.SRC_LAST_UPDATE_DATE
WHERE A.SRC_CREATED_DATE <> B.SRC_CREATED_DATE
AND A.SRC_LAST_UPDATE_DATE <> B.SRC_LAST_UPDATE_DATE;
COMMIT;

这里用ROW_NUMBER()窗口函数给重复组合的记录排序,只取第一条(最新更新的那条),从根源上避免了一对多的匹配问题。

3. 临时关闭并行(应急方案)

如果只是想先绕过并行触发的报错,可以临时关闭并行DML,但这只是权宜之计,重复匹配的核心问题依然存在,不推荐长期使用:

ALTER session disable parallel dml;
-- 去掉Merge语句中的并行提示
MERGE INTO EDWFIN.PSP_LABOR_SCHD_DAY_F_ROLLUP A
USING EDWFIN.PSP_LABOR_SCHD_DAY_F_ROLLUP_FRS_356 B
ON ( A.PAY_RANGE_START_DATE_KEY = B.PAY_RANGE_START_DATE_KEY
AND A.AA_PERSON_NATURAL_KEY = B.AA_PERSON_NATURAL_KEY
AND A.AA_PERSON_ASSIGNMENT_KEY = B.AA_PERSON_ASSIGNMENT_KEY )
WHEN MATCHED THEN UPDATE
SET A.SRC_CREATED_DATE = B.SRC_CREATED_DATE,
A.SRC_LAST_UPDATE_DATE = B.SRC_LAST_UPDATE_DATE
WHERE A.SRC_CREATED_DATE <> B.SRC_CREATED_DATE
AND A.SRC_LAST_UPDATE_DATE <> B.SRC_LAST_UPDATE_DATE;
COMMIT;

最后再提一句:Oracle的Merge操作对源表和目标表的匹配关系有硬性要求——必须是一对一,所以解决问题的核心始终是消除源表的重复匹配项。

内容的提问来源于stack exchange,提问作者karthik

火山引擎 最新活动