使用从属子记录复制表值

时间:2014-01-22 16:48:49

标签: sql oracle parent-child

如果你有一对带有数字主键和父子关系的表,那么在这些表中复制记录的最佳方法是什么,因为如果你把它作为两个单独的插入来实现,那么父键的关键是已经改变了?

或许最好用一个例子来解释。假设您有以下表格结构:

CREATE TABLE APARENT (
  APARENT_CODE NUMBER, -- primary key
  AVALUE1 NUMBER,
  AVALUE2 NUMBER
);

CREATE TABLE ACHILD (
  ACHILD_CODE NUMBER,  -- primary key
  APARENT_CODE NUMBER, -- foreign key
  AVALUE3 NUMBER
);

APARENT中的值是父记录。他们可能在ACHILD表格中有许多记录,并通过APARENT_CODE字段链接回来。

复制记录的最佳方式是什么(包括单个父记录和多个子记录)?我的困惑是因为当您将重复记录插入父表时,您必须更改主键值(在这种情况下通过序列),因此当您插入子记录时,您如何知道链接它们的外键值到?

编辑抱歉,编辑以防不清楚:第一次插入是复制多条记录,因此CURRVAL不能用于第二次插入。

目前我正在使用此代码:

CREATE TABLE TMP_CODES (
  OLD_APARENT_CODE NUMBER,
  NEW_APARENT_CODE NUMBER
);

INSERT INTO TMP_CODES
  SELECT APARENT_CODE,
         SQ_APARENT.NEXTVAL -- gets new sequence value
    FROM APARENT
   WHERE AVALUE1 = 10;

INSERT INTO APARENT
  SELECT C.NEW_APARENT_CODE, -- the copied parent records get a new sequence value
         A.VALUE1,
         A.VALUE2
    FROM APARENT A,
         TMP_CODES C
   WHERE A.AVALUE1 = 10
     AND C.OLD_APARENT_CODE = A.APARENT_CODE;

INSERT INTO ACHILD
  SELECT SQ_ACHILD.NEXTVAL,  -- a new sequence value for the primary key
         C.NEW_APARENT_CODE, -- this inserts the correct link value
         A.VALUE3
    FROM ACHILD A,
         TMP_CODES C
   WHERE C.OLD_APARENT_CODE = A.APARENT_CODE;

我只是想知道是否有更有效的方法,而不是先将所有代码都表达到临时表中。

我正在使用Oracle 10.感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

如果您使用NEXTVAL和CURRVAL作为父表的序列,则不需要临时表。

INSERT INTO APARENT
  SELECT SQ_APARENT.NEXTVAL,
         A.VALUE1,
         A.VALUE2
    FROM APARENT 
   WHERE A.AVALUE1 = 10

INSERT INTO ACHILD
  SELECT SQ_ACHILD.NEXTVAL,  -- a new sequence value for the primary key
         SQ_APARENT.CURRVAL, -- this inserts the correct link value
         A.VALUE3
    FROM ACHILD A
   WHERE A.APARENT_CODE = 10;

答案 1 :(得分:1)

在单个语句中插入行并获取生成的序列值的常用方法是使用RETURNING INTO clause。不幸的是,这个条款是not supported with the multi-row INSERT SELECT statement(截至11.2.0.2.0)。

所以你必须要么:

  • 使用游标并逐行插入父表(然后在子表中为父表中的每一行使用一个多行插入)。

    例如,在您的情况下:

    DECLARE
       l_key aparent.aparent_code%TYPE;
    BEGIN
       FOR cc IN (SELECT a.aparent_code, a.value1, a.value2 
                    FROM aparent a 
                   WHERE a.avalue1 = 10) LOOP
          INSERT INTO aparent 
             VALUES (sq_aparent.nextval, cc.value1, cc.value2) 
             RETURNING aparent_code INTO l_key; -- get the new parent key
          INSERT INTO achild 
             (SELECT sq_achild.nextval, l_key, value3 -- use the new parent key
                FROM achild 
               WHERE aparent_code = cc.aparent_code);
       END LOOP;
    END;
    
  • 使用多行插入和解决方法。

我认为您的方法通常可能是最有效的,特别是如果要复制许多父行。与许多单行语句产生的大量开销相比,插入临时表并加入它的开销应该是最小的。