多桌插入物和斑点的Oracle外国密钥问题
-
08-10-2019 - |
题
我们有一个表,我们希望根据特定的源列分解成表格。我想尝试使用多列插入物,但是看来,如果我将斑点插入子桌子中,我会违反外键约束。
我认为这不违反 有关多桌插入的规则 但是我可能错了...
我希望有人可以将我指向这里实际发生的事情的更多深入资源,以便我可以确信,任何解决方案都可以作为Oracle数据库9i-> 11G上的Liquibase Changeet的一部分工作。
希望简化的方案
CREATE TABLE source (
pk NUMBER NOT NULL PRIMARY KEY,
type VARCHAR2(20) NOT NULL,
content VARCHAR2(20) NOT NULL
);
INSERT INTO source (pk,type,content) values (1,'two','n/a');
INSERT INTO source (pk,type,content) values (2,'one','Content');
CREATE TABLE dest (
pk NUMBER NOT NULL PRIMARY KEY,
type VARCHAR2(20) NOT NULL
);
CREATE TABLE dest_one (
pkfk NUMBER NOT NULL PRIMARY KEY,
data BLOB NOT NULL,
CONSTRAINT XFK1DEST_ONE FOREIGN KEY (pkfk) REFERENCES dest (pk)
);
CREATE TABLE dest_two (
pkfk NUMBER NOT NULL PRIMARY KEY,
CONSTRAINT XFK1DEST_TWO FOREIGN KEY (pkfk) REFERENCES dest (pk)
);
来源包含我们的原始数据。 DEST将是我们的父桌,带有孩子DEST_ONE和DEST_TWO(分别包含有关“一个”或“两个”类型的信息)。一型东西有内容,但第二型事物没有。
失败的尝试
INSERT ALL
WHEN 1=1 THEN INTO dest (pk,type) VALUES (pk,type)
WHEN type='one' THEN INTO dest_one (pkfk,data) VALUES (pk,content)
WHEN type='two' THEN INTO dest_two (pkfk) VALUES (pk)
SELECT pk,type,utl_raw.cast_to_raw(content) as content from source where type in ('one','two');
如前所述,我在这里受到了外国密钥限制的影响。为了进一步说明斑点是我尝试了两个分开的查询(下),意识到一个没有斑点插入的问题,但由于斑点插入失败。
INSERT ALL
WHEN 1=1 THEN INTO dest (pk,type) VALUES (pk,type)
WHEN type='two' THEN INTO dest_two (pkfk) VALUES (pk)
SELECT pk,type,utl_raw.cast_to_raw(content) as content from source where type = 'two';
/* Successful */
INSERT ALL
WHEN 1=1 THEN INTO dest (pk,type) VALUES (pk,type)
WHEN type='one' THEN INTO dest_one (pkfk,data) VALUES (pk,content)
SELECT pk,type,utl_raw.cast_to_raw(content) as content from source where type = 'one';
/* ORA-02291: integrity constraint violated, no parent key */
解决方案1-传统插入物
INSERT INTO dest (pk,type) SELECT pk,type from source where type in ('one','two');
INSERT INTO dest_two (pkfk) SELECT pk from source where type = 'two';
INSERT INTO dest_one (pkfk,data) SELECT pk,utl_raw.cast_to_raw(content) from source where type = 'one';
我正在考虑的一个选择是返回多个单独的插入语句,但是与我在这里说明它们的方式不同,我担心我必须确保我写下我的子表插入件才能尝试插入存在的行在父dest表中...我需要对Liquibase如何处理相同更改中的多个SQL语句进行更多研究。
解决方案2-暂时禁用外键约束
ALTER TABLE dest_one DISABLE CONSTRAINT XFK1DEST_ONE;
当1 = 1插入所有时,然后插入dest(pk,type)值(pk,type)时,当type ='一个'然后插入dest_one(pkfk,data)值(pk,content)时,当type ='二'然后进入dest_two( pkfk)值(PK)选择PK,type,utl_raw.cast_to_raw(content)作为来自源的内容,其中键入('一个'','二');
alter表dest_one启用约束xfk1dest_one;
这是我倾向于的解决方案。在我的斑点表上禁用外键似乎使其在我的测试环境中起作用(10G -10.2.0.1.0),但我不确定我是否也应该在非blob表上禁用外键(由于9i,11g或其他版本的表现如何)。这里的任何资源也将不胜感激。
谢谢一堆!
解决方案
另一个解决方案是将约束评估推迟到提交。我怀疑(但不确定)多桌插件正在按照您期望和想要的插入顺序插入行。重新创建您的约束如下:
ALTER TABLE DEST_ONE DROP CONSTRAINT XFK1DEST_ONE;
ALTER TABLE DEST_ONE
ADD CONSTRAINT XFK1DEST_ONE
FOREIGN KEY (pkfk) REFERENCES dest (pk)
INITIALLY DEFERRED DEFERRABLE;
ALTER TABLE DEST_TWO DROP CONSTRAINT XFK1DEST_TWO;
ALTER TABLE DEST_TWO
ADD CONSTRAINT XFK1DEST_TWO
FOREIGN KEY (pkfk) REFERENCES dest (pk)
INITIALLY DEFERRED DEFERRABLE;
这重新创建了约束,以便可以推迟它们,并从创建时间开始推迟。然后再次尝试您的原始插入物。
分享并享受。