oracle 完整性约束失败错误

acruukt9  于 2023-06-29  发布在  Oracle
关注(0)|答案(1)|浏览(113)

我有一个关于父表和子表的外键约束的问题。我有下面的脚本来从远程数据库插入数据。下面是创建表脚本

CREATE TABLE "S695_LANGUAGE" 
       (    "ID" NUMBER(5,0) GENERATED ALWAYS AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER  NOCYCLE  NOKEEP  NOSCALE , 
        "CODE" NVARCHAR2(5), 
        "DESCRIPTION" NVARCHAR2(50), 
        "IS_ACTIVE" NUMBER(1,0) DEFAULT 1
       ) ;
    
      CREATE TABLE "S695_TEXT_CONTENT" 
       (    "ID" NUMBER(19,0), 
        "TEXT_CONTENT_ID" NVARCHAR2(500)
       );
    
    
      CREATE TABLE "S695_TRANSLATIONS" 
       (    "ID" NUMBER(19,0) GENERATED ALWAYS AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER  NOCYCLE  NOKEEP  NOSCALE , 
        "TEXT_CONTENT_ID" NUMBER(19,0), 
        "LANGUAGE_ID" NUMBER(5,0), 
        "TRANSLATION" NVARCHAR2(500)
       ) 
    
      ALTER TABLE "S695_LANGUAGE" MODIFY ("ID" NOT NULL ENABLE);
      ALTER TABLE "S695_LANGUAGE" ADD CONSTRAINT "S695_LANGUAGE_PK" PRIMARY KEY ("ID");
    
    
      ALTER TABLE "S695_TEXT_CONTENT" ADD CONSTRAINT "S695_TEXT_CONTENT_PK" PRIMARY KEY ("ID");
      ALTER TABLE "S695_TRANSLATIONS" MODIFY ("ID" CONSTRAINT "S695_TRANSLATIONS_CK_ID_NOT_NULL" NOT NULL ENABLE);
      ALTER TABLE "S695_TRANSLATIONS" ADD CONSTRAINT "S695_TRANSLATIONS_PK" PRIMARY KEY ("ID");
      ALTER TABLE "S695_TRANSLATIONS" ADD CONSTRAINT "S695_TRANSLATIONS_TEXT_CONTENT_ID_FK" FOREIGN KEY ("TEXT_CONTENT_ID")
          REFERENCES "S695_TEXT_CONTENT" ("ID") ENABLE;
      ALTER TABLE "S695_TRANSLATIONS" ADD CONSTRAINT "S695_TRANSLATIONS_LANGUAGE_FK" FOREIGN KEY ("LANGUAGE_ID")
          REFERENCES "S695_LANGUAGE" ("ID") ENABLE;

Here the language table and translation table have a constraint relationship on language id field.
DECLARE
    v_seq_name   VARCHAR2(20);
    v_str        VARCHAR2(200);
    v_val        NUMBER;
     v_Nederlands_LanguageId NUMBER(5);
     v_French_LanguageId NUMBER(5);
     v_English_LanguageId NUMBER(5);
     v_Deutsch_LanguageId NUMBER(5);
     v_TextContent_Id NUMBER(19);
    V_MAX_TEXT_CONTENT_ID NUMBER(19);
BEGIN

    SELECT
        sequence_name
    INTO v_seq_name
    FROM
        user_tab_identity_cols@DBLINK1
    WHERE
        table_name = 'S695_LANGUAGE';

    v_str := 'select '
             || v_seq_name
             || '.nextval@DBLINK1 from dual';
    dbms_output.put_line('v_str = ' || v_str);
    EXECUTE IMMEDIATE v_str
    INTO v_Nederlands_LanguageId;
    dbms_output.put_line('Value = ' || v_val);
    INSERT INTO s695_language@DBLINK1 (
        code,
        description,
        is_active
    ) VALUES (
        'NL',
        'NEDERLANDS',
        '1'
    );

    INSERT INTO s695_RESERVATION_language@DBLINK2 (
        id,
        code,
        description,
        is_active
    ) VALUES (
        v_Nederlands_LanguageId,
        'NL',
        'NEDERLANDS',
        '1'
    );

   
    -- Channel
   --commit;
   
    SELECT S695_TEXT_CONTENT_SEQ.NEXTVAL@DBLINK1 INTO v_TextContent_Id FROM DUAL;  
     
     INSERT INTO S695_TEXT_CONTENT@DBLINK1 (ID,TEXT_CONTENT_ID) VALUES(v_TextContent_Id,CONCAT(u'TextContent_',v_TextContent_Id));  
    
   select max(id)  into V_MAX_TEXT_CONTENT_ID from S695_TEXT_CONTENT@DBLINK1;
     INSERT INTO S695_RESERVATION_TEXT_CONTENT@DBLINK2 (ID,TEXT_CONTENT_ID) VALUES(V_MAX_TEXT_CONTENT_ID,CONCAT(u'TextContent_',V_MAX_TEXT_CONTENT_ID));  
     
    INSERT INTO S695_TRANSLATIONS@DBLINK1(TEXT_CONTENT_ID,LANGUAGE_ID,TRANSLATION) VALUES(V_MAX_TEXT_CONTENT_ID,v_Nederlands_LanguageId,u'MobileApp');
     INSERT INTO S695_RESERVATION_TRANSLATIONS@DBLINK2(TEXT_CONTENT_ID,LANGUAGE_ID,TRANSLATION) VALUES(V_MAX_TEXT_CONTENT_ID,v_Nederlands_LanguageId,u'MobileApp');
 
    INSERT INTO S695_CHANNEL@DBLINK1(CODE,DESCRIPTION,TEXT_CONTENT_ID,IS_ACTIVE) VALUES (u'MO', u'MobileApp', V_MAX_TEXT_CONTENT_ID, 1);
    INSERT INTO S695_RESERVATION_CHANNEL@DBLINK2  (CODE,DESCRIPTION,TEXT_CONTENT_ID,IS_ACTIVE) VALUES (u'MO', u'MobileApp', V_MAX_TEXT_CONTENT_ID, 1);
         commit;
 --rollback;
END;
/

分布式更新操作失败;需要回滚。ORA-02291:已违反完整性约束(S695_TRANSLATIONS_LANGUAGE_FK)-找不到父项。
它看起来像插入到语言表没有提交,因为它给了一个外键约束违反。(我认为)

vsdwdz23

vsdwdz231#

被违反的外键是:

ALTER TABLE "S695_TRANSLATIONS"
  ADD CONSTRAINT "S695_TRANSLATIONS_LANGUAGE_FK"
  FOREIGN KEY ("LANGUAGE_ID") REFERENCES "S695_LANGUAGE" ("ID") ENABLE;

使用时:

'select ' || v_seq_name || '.nextval@DBLINK1 from dual';

它将当前序列值递增1并返回该值。
执行INSERT时:

INSERT INTO s695_language@DBLINK1 (code, description, is_active)
VALUES ('NL', 'NEDERLANDS', '1');

然后自动生成ID列,它将序列号再增加1并插入新值。
然后,当您插入转换表时,您使用的序列值是手动生成的,并且等于插入表中的值,因此您试图引用错误的id值。
使用RETURNING ... INTO

DECLARE
   v_Nederlands_LanguageId NUMBER(5);
BEGIN
  INSERT INTO s695_language@DBLINK1 (code, description, is_active)
  VALUES ('NL', 'NEDERLANDS', '1')
  RETURNING id INTO v_Nederlands_LanguageId;

  INSERT INTO s695_RESERVATION_language@DBLINK2 (id, code, description, is_active)
  VALUES (v_Nederlands_LanguageId, 'NL', 'NEDERLANDS', '1');
END;
/

但是,RETURNING ... INTO子句可能不受DB链路的支持。
要解决这个问题,可以在远程数据库上创建一个过程,并在该过程中使用RETURNING ... INTO ...,这样就不必使用DB链接(除了调用该过程)。
另一种方法是用途:

'select ' || v_seq_name || '.currval@DBLINK1 from dual';

插入到语言表后得到当前序列值。
如果你有一个小批量的插入从一个单一的用户,那么这可能会工作;然而,如果你有来自多个用户的插入,并且它们几乎同时发生,那么你可能会发现两个用户同时执行INSERT到语言表中,序列号增加两次,当他们读取当前值时,他们都得到相同的序列值。用一种健壮的方式来解决这个问题可能会更好,使用RETURNING ... INTO,而不是使用一种只在某些环境中有效的方法。

相关问题