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

如何创建Oracle存储过程实现多步表规范化操作

Oracle存储过程实现表规范化三步操作

需要开发一个Oracle存储过程,完成以下三步表规范化操作:

  • 步骤1:从百万级数据的temp表中提取重复的(address, key)组合,将去重后的这类数据插入同表,设置ver_id = -1,ID由序列seq_temp生成
  • 步骤2:更新父表ADDRESS_TEMP,将对应重复记录的pid关联到步骤1生成的新ID
  • 步骤3:删除temp表中ver_id ≠ -1的重复记录,仅保留ver_id = -1的合并记录和无重复的原始记录

现有代码问题分析

提供的p1存储过程存在严重逻辑与性能问题:通过游标遍历整个temp表,每次循环都执行插入逻辑,会导致同一组重复的(address, key)被多次插入,完全不符合需求;同时百万级数据下,游标循环会造成极大的性能损耗,必须重构为批量处理逻辑。


完整存储过程实现

CREATE OR REPLACE PROCEDURE p_normalize_temp AS
    -- 定义集合存储步骤1生成的新记录关联关系
    TYPE rec_map IS RECORD (
        address temp.address%TYPE,
        key     temp.key%TYPE,
        new_pid temp.id%TYPE
    );
    TYPE map_table IS TABLE OF rec_map;
    v_map map_table;
BEGIN
    -- 事务包裹,确保三步操作原子性
    BEGIN
        -- 步骤1:提取重复组合并插入新记录,同时保存映射关系
        WITH duplicate_groups AS (
            SELECT DISTINCT address, key
            FROM (
                SELECT t.*,
                       ROW_NUMBER() OVER (PARTITION BY address, key ORDER BY id) rn
                FROM temp t
            )
            WHERE rn > 1
        ),
        inserted_records AS (
            INSERT INTO temp (id, address, key, ver_id)
            SELECT seq_temp.nextval, address, key, -1
            FROM duplicate_groups
            RETURNING address, key, id INTO v_map
        )
        SELECT * FROM inserted_records; -- 触发INSERT并填充映射集合

        -- 步骤2:批量更新父表关联关系
        FORALL i IN v_map.FIRST..v_map.LAST
            UPDATE ADDRESS_TEMP atemp
            SET atemp.pid = v_map(i).new_pid
            WHERE EXISTS (
                SELECT 1 FROM temp t
                WHERE t.id = atemp.pid
                  AND t.address = v_map(i).address
                  AND t.key = v_map(i).key
                  AND t.ver_id != -1
            );

        -- 步骤3:精准删除原始重复记录
        DELETE FROM temp
        WHERE ver_id != -1
          AND EXISTS (
              SELECT 1 FROM temp t
              WHERE t.address = temp.address
                AND t.key = temp.key
                AND t.ver_id = -1
          );

        COMMIT;
    EXCEPTION
        WHEN OTHERS THEN
            ROLLBACK;
            RAISE; -- 抛出异常便于上层处理
    END;
END p_normalize_temp;
/

关键实现说明

  1. 步骤1优化:使用WITH子句一次性识别所有重复组,通过RETURNING子句将新插入记录的关联关系存入集合,避免后续重复查询,提升性能
  2. 步骤2批量更新:采用FORALL语句批量处理父表更新,相比单条更新,百万级数据下性能提升显著
  3. 事务控制:三步操作包裹在事务中,确保数据一致性,要么全部成功,要么全部回滚
  4. 步骤3精准删除:仅删除存在对应ver_id=-1合并记录的原始重复项,自动保留无重复的原始记录(如示例中的pid=4)

示例数据验证

  • 步骤1执行后:temp表新增pid=5的记录(address=242 Street, key=123, ver_id=-1),与预期一致
  • 步骤2执行后:ADDRESS_TEMP中原pid为1、2、3的记录,pid字段会被更新为5,符合关联逻辑
  • 步骤3执行后:temp表中pid=1、2、3的记录被删除,仅保留pid=4和5的记录,与预期结果一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 06:55:25