You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用Oracle存储过程报ORA-01422错误 重复ID写入cmb_reject表问题

ORA-01422报错根因

报错的直接原因是你写的select e_id into lv_count from cmb_staging;语句返回了多行数据:INTO语法要求查询结果必须唯一且只有1行,而你的cmb_staging表有多条记录,这条查询会返回所有行的e_id,自然触发多行返回错误。同时这条查询的逻辑本身也不符合你的需求,你原本想要统计重复e_id的数量,实际写的是查询全表e_id值,逻辑完全不匹配。

此外你原代码还有多个逻辑漏洞:

  • 没有对重复e_id的记录做校验失败标记,仅做了空值、长度超限的校验
  • IF分支逻辑完全错误,哪怕计数逻辑改对也无法实现你要的「重复记录进reject表、合法记录进目标表」的需求
  • 直接用未去重的数据源跑MERGE,必然会触发ORA-30926(你提到的ORA-30296属于笔误),因为同一个目标行匹配到多个源行时,Oracle无法确定用哪个源数据更新。

修复后的完整存储过程

调整逻辑为:先做全量校验(含空值、长度超限、e_id重复三种规则),校验失败的记录统一进reject表,校验通过的唯一e_id记录走MERGE入目标表,避免MERGE报错。

create or replace procedure sp_dup_rec(ov_err_msg OUT varchar2)
is
    lv_succ_rec number(30);
    lv_fail_rec number(30);
begin
    lv_succ_rec := 0;
    lv_fail_rec := 0;

    -- 第一步:基础校验:e_id为空/长度超过4,标记为失败
    UPDATE cmb_staging
    SET validation_status = 'Fail',
        validation_result = CASE
                            WHEN e_id IS NULL THEN 'Id is not present'
                            ELSE 'Id is longer than expected'
                            END
    WHERE e_id is null
    OR LENGTH(e_id) > 4;

    -- 第二步:重复e_id校验:所有出现次数>1的e_id对应的记录,标记为失败
    UPDATE cmb_staging s
    SET validation_status = 'Fail',
        validation_result = 'e_id重复'
    WHERE validation_status IS NULL -- 已经标记失败的不用再判断
    AND EXISTS (
        SELECT 1 FROM cmb_staging s2
        WHERE s2.e_id = s.e_id
        GROUP BY s2.e_id
        HAVING COUNT(*) > 1
    );

    -- 第三步:所有校验失败的记录插入reject表
    INSERT INTO cmb_reject
    SELECT s.*
    FROM cmb_staging s
    WHERE validation_status = 'Fail';
    lv_fail_rec := SQL%ROWCOUNT;

    -- 第四步:校验通过的记录(e_id合法且唯一)MERGE到目标表,不会再触发MERGE重复匹配错误
    MERGE INTO cmb_target t
    USING (
        SELECT e_id, e_name, e_loc
        FROM cmb_staging
        WHERE validation_status IS NULL
    ) S
    ON (t.e_id = S.e_id)
    WHEN MATCHED THEN UPDATE SET 
        t.e_name = s.e_name,
        t.e_loc = s.e_loc
    WHEN NOT MATCHED THEN INSERT (t.e_id,t.e_name,t.e_loc)
        VALUES (s.e_id,s.e_name,s.e_loc);
    lv_succ_rec := SQL%ROWCOUNT;

    -- 第五步:写入汇总表
    dbms_output.put_line('Inserting into Summary table');
    INSERT INTO summary_tab(
        tot_records,
        success_records,
        failed_records,
        process_status
    ) values (
        lv_succ_rec + lv_fail_rec,
        lv_succ_rec,
        lv_fail_rec,
        'COMPLETED'
    );

    COMMIT;
    ov_err_msg := 'Procedure completed succesfully';
EXCEPTION
    WHEN OTHERS THEN
        ov_err_msg := 'Procedure end up with errors:'|| sqlerrm;
        ROLLBACK;
END sp_dup_rec;

修复后验证

你可以直接用原来的调用语句执行,你的测试数据中e_id=1、e_id=2都是重复的,会被标记为失败进reject表,只有e_id=3的唯一合法记录会进入目标表,不会再出现ORA-01422和MERGE相关报错。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 19:06:06