插入1:1替代品

时间:2019-06-06 04:33:27

标签: oracle sql-insert

我有两个桌子。表A和B每个都有一个自动递增的主键,外键不能为null。两个表都处于1:1关系。

因此,对于A中的每个记录,必须有一个B。

我无法工作的是插入到这样的表中。我得到的错误是“找不到父键”。

我是oracle的新手,所以谢谢您的帮助。

这是ER的屏幕: enter image description here

这是我的插入内容:

INSERT ALL
INTO NASTAVENI_TARIFU (ZADANI_D, ID_OBJEDNAVKY, ID_DODATKU, ID_TARIF, ID_NABIDKY) VALUES (TO_DATE('2018-01-01', 'yyyy-mm-dd' ), 1, SQ_SMLUVNI_DODATEK.nextval, 2, NULL)
INTO SMLUVNI_DODATKY (PROLONGACE_D,ID_NASTAVENI_TARIFU) VALUES (TO_DATE('2019-12-22', 'yyyy-mm-dd' ), SQ_NASTAVENI_TARIFU.currval)
SELECT * FROM DUAL

以下是定义:

CREATE TABLE nastaveni_tarifu (
    id_nastaveni_tarifu   INTEGER NOT NULL,
    zadani_d              DATE NOT NULL,
    id_objednavky         INTEGER NOT NULL,
    id_dodatku            INTEGER NOT NULL,
    id_tarif              INTEGER NOT NULL,
    id_nabidky            INTEGER
);

CREATE TABLE smluvni_dodatky (
    id_dodatku            INTEGER NOT NULL,
    prolongace_d          DATE NOT NULL,
    id_nastaveni_tarifu   INTEGER NOT NULL
);

ALTER TABLE smluvni_dodatky
    ADD CONSTRAINT fk_dodatek_nast_tarifu FOREIGN KEY ( id_nastaveni_tarifu )
        REFERENCES nastaveni_tarifu ( id_nastaveni_tarifu );

ALTER TABLE nastaveni_tarifu
    ADD CONSTRAINT fk_nast_tarifu_dodatek FOREIGN KEY ( id_dodatku )
        REFERENCES smluvni_dodatky ( id_dodatku );

CREATE SEQUENCE sq_nastaveni_tarifu START WITH 1 MINVALUE 1 NOCACHE ORDER;

CREATE OR REPLACE TRIGGER tr$ntpreinsert BEFORE
    INSERT ON nastaveni_tarifu
    FOR EACH ROW
    WHEN ( new.id_nastaveni_tarifu IS NULL )
BEGIN
    :new.id_nastaveni_tarifu := sq_nastaveni_tarifu.nextval;
END;

CREATE SEQUENCE sq_smluvni_dodatek START WITH 1 MINVALUE 1 NOCACHE ORDER;

CREATE OR REPLACE TRIGGER tr$sdpreinsert BEFORE
    INSERT ON smluvni_dodatky
    FOR EACH ROW
    WHEN ( new.id_dodatku IS NULL )
BEGIN
    :new.id_dodatku := sq_smluvni_dodatek.nextval;
END;

...我开始讨厌Oracle,这不应该那么难:(

1 个答案:

答案 0 :(得分:3)

正如我提到的,这是一个糟糕的设计,因为两个表之间存在循环引用。

您的insert all语句存在的问题是,第二个into子句无法看到SQ_NASTAVENI_TARIFU.nextval,因为只有在整个语句完成时才能对其进行初始化。

即使将其转换为2个insert语句,也不会起作用,因为在每种情况下值都依赖于另一个时,您无法确保在一个表中有一行,并且还声明了外键列not null

您可以将它们定义为NULL,然后尝试先插入null,然后对其进行更新,或者仅将Deferred Constraints用作解决方法

ALTER TABLE smluvni_dodatky
    ADD CONSTRAINT fk_dodatek_nast_tarifu FOREIGN KEY ( id_nastaveni_tarifu )
        REFERENCES nastaveni_tarifu ( id_nastaveni_tarifu ) 
    deferrable initially deferred;


ALTER TABLE nastaveni_tarifu
    ADD CONSTRAINT fk_nast_tarifu_dodatek FOREIGN KEY ( id_dodatku )
        REFERENCES smluvni_dodatky ( id_dodatku ) deferrable initially deferred;

现在,第二个触发器还有另一个问题,除非使用序列smluvni_dodatky生成的表sq_smluvni_dodatek的主键可以存储插入到nastaveni_tarifu中的相同值,否则不能保持恒定。

在触发器tr$sdpreinsert中,将赋值表达式更改为此

:new.id_dodatku := sq_smluvni_dodatek.currval;

现在,将这两个插入操作作为单独的语句运行将是可行的,因为在发出 commit之前,不会进行约束检查。

  INSERT   INTO nastaveni_tarifu (
          zadani_d,id_objednavky,id_dodatku,id_tarif,id_nabidky
     ) VALUES (
          TO_DATE('2018-01-01','yyyy-mm-dd'), 1,sq_smluvni_dodatek.NEXTVAL, 2,NULL
     ) ;
 INSERT INTO smluvni_dodatky (
          prolongace_d,id_nastaveni_tarifu
     ) VALUES (
          TO_DATE('2019-12-22','yyyy-mm-dd'),sq_nastaveni_tarifu.currval);
commit;

DEMO