【问题标题】:Cascade INSERT using SEQUENCE - ORACLE使用 SEQUENCE 级联插入 - ORACLE
【发布时间】:2014-08-04 04:50:07
【问题描述】:

我需要从两个表中复制记录并再次将它们重新插入到这些表中,只有一个字段不同(父表的 PK,子表的 PK 和 FK)。 PK可以取自SEQUENCE,我面临的问题是如何级联更新子表中的FK。

我有下表 My_List,其中 Sup_ID 是主键

我的列表

+--------+----------+------------+
| Sup_ID | Sup_Name | Sup_Code |
+--------+----------+------------+
| 1 |机管局 | 23 |
| 2 | BB | 87 |
| 3 |抄送 | 90 |
+--------+----------+------------+

还有下表My_List_details,其中Buy_ID是主键(取自SEQUENCE,假设已经创建),Sup_ID是外键点在 My_List.Sup_ID

My_List_details

+--------+--------+------------+------------+-- ----------+
|购买_ID | Sup_ID | Sup_Detail |最大金额 |最小金额 |
+--------+--------+------------+------------+----- --------+
| 33 | 1 | AAA | 1 | 10 |
| 34 | 2 |血脑屏障 | 11 | 20 |
| 35 | 3 | CCC | 21 | 30 |
| 36 | 2 |血脑屏障 | 11 | 20 |
+--------+--------+------------+------------+----- --------+

------------------------------------------ --------

目标

编写 PL/SQL 函数执行以下操作:

  1. 复制 My_List 记录并重新插入,然后使用取自 SEQUENCE 的新 PK -> Sup_ID 值。
  2. 复制 My_List_details 记录并根据 My_List.Sup_ID 和 SEQUENCE 中的 Buy_ID 使用新的 Sup_ID 外键重新插入它们。

------------------------------------------ ----------------------------------

预期结果

我的列表

+--------+----------+----------+
| Sup_ID | Sup_Name | Sup_Code |
+--------+----------+----------+
| 1 |机管局 | 23 |
| 2 | BB | 87 |
| 3 |抄送 | 90 |
| 4 |机管局 | 23 |
| 5 | BB | 87 |
| 6 |抄送 | 90 |
+--------+----------+----------+

My_List_details

+--------+--------+------------+------------+-- ----------+
|购买_ID | Sup_ID |子_详细 |最大金额 |最小金额 |
+--------+--------+------------+------------+----- --------+
| 33 | 1 | AAA | 1 | 10 |
| 34 | 2 |血脑屏障 | 11 | 20 |
| 35 | 3 | CCC | 21 | 30 |
| 36 | 2 |血脑屏障 | 11 | 20 |
| 37 | 1 | AAA | 1 | 10 |
| 38 | 2 |血脑屏障 | 11 | 20 |
| 39 | 3 | CCC | 21 | 30 |
| 40 | 2 |血脑屏障 | 11 | 20 |
+--------+--------+------------+------------+----- --------+

我开始的内容如下:

BEGIN
    FOR   d  IN (
                    SELECT  Sup_Name, Sup_Code
                    FROM    My_List
                )
    LOOP
        INSERT INTO MY_List SELECT Sup_ID.NEXTVAL, Sup_Name, Sup_Code 
    END LOOP;
END;
/

但是,我不确定以下几点:

  • 如何将 My_List_Details 中的 FK 替换为 My_List 中 PK 的新值。 My_List_Detail
  • 扩展函数更新任意数量的子表(级联更新),(如5个表的FK指向My_List的PK,需要以相同的方式更新)。

【问题讨论】:

  • 您可以使用insert 语句的returning into 子句来获取刚刚插入的sup_id 列的值,或者引用sequence_name.currval 来获取序列的当前值。
  • @NicholasKrasnov Sup_id in My_List_details 是 FK,因此它随机重复不止一次。我找不到 returning into 会用新的 FK 替换每个旧的 FK。我更新了第二张表以反映这一特点。
  • 您是否尝试实现更改历史记录?
  • @Franek 我不确定我是否明白你的意思,但基本上我尝试将 My_List 表记录的另一个副本插入到同一个表中。当然,这需要插入不同的PK值。因此,所有相关的 FK 值也需要更新

标签: sql oracle plsql


【解决方案1】:

我认为好的解决方案是通过附加列扩展所有主键,当克隆记录发生时,该列将由触发器递增。 我们将此附加列称为 SEC_ID。 SEC_ID 应递增并仅在一个主键的上下文中使用。 您不必在表中创建与 SEC_ID 列一样多的序列。您可以在触发器中查询您的 ID 的最后一个 sec_id,然后将其递增以插入具有原始 ID 的新有效主键。

优点:

简单的机制

新表的简单扩展

【讨论】:

  • 我明白了,但是如何将 PK 映射到 My_List_Details 表中新插入的记录中的 FK。 My_list 和 My_list_details 之间的关系是 1..*,因此,My_List_Details 的 FK 不遵循 My_List 的 PK 的相同数量和顺序
【解决方案2】:

我发现以下解决了我的问题(假设 sup_seq 和 buy_seq 是两个创建的序列):

DECLARE
   CURSOR cOld IS
      SELECT *
      FROM my_list;

   new_id  NUMBER;
BEGIN
   FOR rOld IN cOld LOOP
      new_id := sup_seq.NEXTVAL;  -- Get the ID to use for the new row

      INSERT INTO my_list
             (sup_id,sup_name,sup_code)
      VALUES (new_id,rOld.sup_name,rOld.sup_code);

      INSERT INTO my_list_details
            (buy_id,sup_id,sup_detail,max_amount,min_amount)
      SELECT buy_seq.NEXTVAL,new_id,sup_detail,max_amount,min_amount
      FROM   my_list_details
      WHERE  sup_id = rOld.sup_id;
   END LOOP;
END;

如果问题可以通过其他方式解决,可能不建议使用光标,对我来说,我发现它更易于阅读和维护。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-15
    • 2018-12-27
    相关资源
    最近更新 更多