【问题标题】:Copying table values with dependent child records复制具有依赖子记录的表值
【发布时间】:2014-01-22 16:48:49
【问题描述】:

如果您有一对具有数字主键和父子关系的表,那么在这些表中复制记录的最佳方法是什么,如果您将其作为两个单独的插入操作,则父键将变了吗?

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

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。感谢您的帮助。

【问题讨论】:

    标签: sql oracle parent-child


    【解决方案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;
      
    • 像您一样使用多行插入和解决方法。

    我认为您的方法通常可能是最有效的,尤其是在复制许多父行的情况下。与许多单行语句所产生的大量开销相比,插入临时表和加入临时表的开销应该是最小的。

    【讨论】:

      【解决方案2】:

      如果您使用 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;
      

      【讨论】:

      • 如果第一次插入很多记录,这是否正确?我相信 CURRVAL 只是指最近的值,不会针对之前的值进行调整。
      • 抱歉,是的,这适用于单行插入,但目的是用于多行插入。我已经澄清了这个问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多