我们有一个表,我们希望根据特定的源列将其分解为表树。我想尝试使用多列插入,但似乎如果我将 blob 插入子表中,我最终会违反外键约束。
我不认为这违反了关于多表插入的规则,但我可能是错的......
我希望有人可以向我指出一些关于这里实际发生的更深入的资源,这样我就可以确信任何解决方案都可以作为 Oracle 数据库 9i -> 11g 上的 liquibase 变更集的一部分。
希望简化的场景
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)
);
Source 包含我们的原始数据。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');
如前所述,我在这里遇到了外键约束违规。为了进一步说明 blob 是问题所在,我尝试了两个单独的类似查询(如下),实现了一个没有 blob 插入的查询有效,但 blob 插入失败。
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;
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');
ALTER TABLE dest_one ENABLE CONSTRAINT XFK1DEST_ONE;
这是我倾向于的解决方案。虽然在我的 blob 表上禁用外键似乎使它在我的测试环境(10g - 10.2.0.1.0)中工作,但我不确定我是否也应该在非 blob 表上禁用外键(由于 9i、11g 或 10g 的其他版本的行为方式)。这里的任何资源也将不胜感激。
非常感谢!