使用PL / SQL复制和级联插入

时间:2014-08-01 08:43:33

标签: sql oracle plsql

鉴于数据结构:

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

My_List

+--------+----------+-----------+
| Sup_ID | Sup_Name |  Sup_Code |
+--------+----------+-----------+
|      1 | AA       |        23 |
|      2 | BB       |        87 |
|      3 | CC       |        90 |
+--------+----------+-----------+

下表 _MyList_details ,其中 Buy_ID 是主键,而 Sup_ID My_List.Sup_ID

My_List_details

+--------+--------+------------+------------+------------+
| Buy_ID | Sup_ID | Sup_Detail | Max_Amount | Min_Amount |
+--------+--------+------------+------------+------------+
|     23 |      1 | AAA        |          1 |         10 |
|     33 |      2 | BBB        |         11 |         20 |
|     43 |      3 | CCC        |         21 |         30 |
+--------+--------+------------+------------+------------+

最后,我有 My_Sequence 表格如下:

My_Sequence

+-----+------+
| Seq | Name |
+-----+------+
|   4 | x    |
|   5 | y    |
|   6 | z    |
+-----+------+

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

目标

将PL / SQL脚本写入:

  1. 使用游标,我需要复制 My_List 记录并使用从 My_Sequence.Seq 复制的新 Sup_ID 重新插入。< / LI>
  2. 我需要复制 My_List_details 记录并使用新的 Sup_ID 外键重新插入它们。
  3. -------------------------------------------- ----------------------------------

    预期结果

    My_List

    +--------+----------+----------+
    | Sup_ID | Sub_Name | Sub_Code |
    +--------+----------+----------+
    |      1 | AA       |       23 |
    |      2 | BB       |       87 |
    |      3 | CC       |       90 |
    |      4 | AA       |       23 |
    |      5 | BB       |       87 |
    |      6 | CC       |       90 |
    +--------+----------+----------+

    My_List_details

    +--------+--------+------------+------------+------------+
    | Buy_ID | Sup_ID | Sub_Detail | Max_Amount | Min_Amount |
    +--------+--------+------------+------------+------------+
    |     23 |      1 | AAA        |          1 |         10 |
    |     33 |      2 | BBB        |         11 |         20 |
    |     43 |      3 | CCC        |         21 |         30 |
    |     53 |      4 | AAA        |          1 |         10 |
    |     63 |      5 | BBB        |         11 |         20 |
    |     73 |      6 | CCC        |         21 |         30 |
    +--------+--------+------------+------------+------------+

    我开始的是以下内容:

    DECLARE
      NEW_Sup_ID Sup_ID%type := Seq;
      c_Sup_Name Sup_Name%type;
      c_Sup_Code Sup_Code%type;
      c_Buy_ID Buy_ID%type;
      c_Sup_Detail Sup_Detail%type;
      c_Max_Amount Max_Amount%type
      c_My_Min_Amount Min_Amount%type
    
      CURSOR c_My_List
      IS
        SELECT * FROM My_List;
      CURSOR c_My_List_details
      IS
        SELECT * FROM My_List_details 
      BEGIN
        FETCH c_My_List INTO NEW_Sup_ID, c_Sup_Name, c_Sup_Code;
        INSERT INTO My_List;
        FETCH c_My_List_details INTO c_Buy_ID, NEW_Sup_ID, c_Sup_Detail, c_Max_Amount, c_Min_Amount
        INSERT INTO My_List_details 
      END;
    /
    

    除了语法错误之外,我没有看到我的脚本逐行复制并相应地将它们插入到两个表中。此外, My_Sequence 记录的数量大于 My_List 记录的数量。所以我需要的是,如果 My_List 记录是50,我需要脚本从 My_Sequence 复制前50个 Seq

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

    问题

    如何实现这一结果?我搜索并发现了Tom Kyte级联更新,但我不确定是否需要使用此软件包,我是PL / SQL的初学者,使用这样一个全面的软件包对我来说有点复杂。此外,它是级联更新,我的情况是重新插入。我很感激任何帮助

2 个答案:

答案 0 :(得分:2)

以下Sql语句将对this SqlFiddle中定义的架构执行任务。请注意,我更改了几个字段和表名 - 因为它们与Oracle术语冲突。 SqlFiddle似乎在我的代码中遇到了一些问题,但它已经在另一个(两栖)客户端上进行了测试,该客户端仍然是无名的。

关键点(正如我在评论中所说)是推导出将旧序列号映射到新序列的规则。视图SEQUENCE_MAP在以下查询中执行此任务。

您可能对我的回复感到失望,因为它取决于与LIST/LIST_DETAILS存在完全相同的序列记录数,因此它只能运行一次。我希望你的最终PL / SQL可以执行必要的检查。

希望这是一个改进sequence_map逻辑的问题,让你到达你想去的地方。

避免使用游标;理想情况下,在操作关系数据时,您需要根据数据集而不是行进行思考。这是因为如果你使用集合思维,Oracle可以在优化,并行化等方面发挥其魔力。 Oracle在扩展方面非常出色 - 例如,如果一个表分散在多个磁盘上,它可能会同时处理来自多个磁盘的数据的请求。如果你强制它逐行,程序逻辑,你可能会发现你编写的应用程序不能很好地扩展。

CREATE OR REPLACE VIEW SEQUENCE_MAP AS ( 
    SELECT OLD_SEQ, NEW_SEQ FROM
    ( 
      ( SELECT ROWNUM AS RN, SUP_ID AS OLD_SEQ FROM
        (SELECT SUP_ID FROM LIST ORDER BY SUP_ID) ) O 
      JOIN
      ( SELECT ROWNUM AS RN, SUP_ID AS NEW_SEQ  FROM 
        (SELECT SEQ AS SUP_ID FROM SEQUENCE_TABLE ORDER BY SEQ) ) N
      ON N.RN = O.RN 
    ) 
  );  

INSERT INTO LIST
( 
 SELECT 
   NEW_SEQ, SUB_NAME, SUB_CODE  
 FROM 
  SEQUENCE_MAP  
  JOIN LIST L ON
    L.SUP_ID = SEQUENCE_MAP.OLD_SEQ 
);

INSERT INTO LIST_DETAILS
( 
 SELECT 
    BUY_ID, NEW_SEQ, SUB_DETAIL, MAX_FIELD, MIN_FIELD   
 FROM 
   SEQUENCE_MAP  
   JOIN LIST_DETAILS L ON
     L.SUP_ID = SEQUENCE_MAP.OLD_SEQ   
);

答案 1 :(得分:1)

我会做2个内循环,并搜索下一个要使用的序列。

我想新的buy_id是通过触发器使用序列或类似的东西来分配的,否则你必须在你的代码中生成它。

我没有可用的Oracle数据库来测试它,所以不要注意语法。

DECLARE
  NEW_Sup_ID Sup_ID%type := Seq;
  c_Sup_ID Sup_ID%type := Seq;
  c_Sup_Name Sup_Name%type;
  c_Sup_Code Sup_Code%type;
  c_Buy_ID Buy_ID%type;
  c_Sup_Detail Sup_Detail%type;
  c_Max_Amount Max_Amount%type;
  c_My_Min_Amount Min_Amount%type;
  CURSOR c_My_List
  IS
    SELECT * FROM My_List;
  CURSOR c_My_List_details
  IS
    SELECT * FROM My_List_details where sup_id=c_Sup_ID;
  BEGIN
    for c_My_List IN c_Sup_ID, c_Sup_Name, c_Sup_Code loop
    select min(seq) from My_sequence into NEW_Sup_ID;
    INSERT INTO My_List (sup_id,...) values (NEW_Sup_ID,...);
    for  c_My_List_details IN c_Buy_ID, NEW_Sup_ID, c_Sup_Detail, c_Max_Amount, c_Min_Amount loop
    INSERT INTO My_List_details (sup_id, ...) values (NEW_Sup_ID,...);
    end loop;
    deelte from  from My_sequence where seq= NEW_Sup_ID;
    end loop;
    commit;
  END;
/