我有两个桌子。表A和B每个都有一个自动递增的主键,外键不能为null。两个表都处于1:1关系。
因此,对于A中的每个记录,必须有一个B。
我无法工作的是插入到这样的表中。我得到的错误是“找不到父键”。
我是oracle的新手,所以谢谢您的帮助。
这是我的插入内容:
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,这不应该那么难:(
答案 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;