マルチテーブルインサートとブロブに関するOracle外部キーの問題
-
08-10-2019 - |
質問
特定のソース列に基づいて、テーブルのツリーに分割したい単一のテーブルがあります。マルチコラムインサートを使用してみたかったのですが、サブテーブルにブロブを挿入すると、外部のキー制約違反で巻き上げられるようです。
これが違反しているとは思わない マルチテーブルインサートに関するルール しかし、私は間違っている可能性があります...
私は、誰かが実際にここで起こっていることに関するいくつかの詳細なリソースを私に向けてくれることを望んでいます。そうすれば、オラクルデータベース9i-> 11gでリキバーゼの変更の一部としてどのソリューションが機能するかを確信できるようになりました。
うまくいけば、シンプルなシナリオ
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(それぞれ「1」または「2」のものに関する情報が含まれます)を含む親のテーブルとなります。タイプ1のものにはコンテンツがありますが、タイプ2のものはありません。
失敗した試み
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インサートが失敗した場合、2つの同様のクエリ(以下)を試しました(以下)。
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';
私が検討している1つのオプションは、複数の個別の挿入ステートメントに戻ることですが、ここでそれらを述べた方法とは異なり、存在する行のみを挿入しようとするためにサブテーブルインサートを書くことを確認する必要があることを心配していますParent Dest Tableでは、同じChangesetでリキバースが複数のSQLステートメントを処理する方法についてさらに調査する必要があります。
ソリューション2-外部キーの制約を一時的に無効にします
ALTER TABLE dest_one DISABLE CONSTRAINT XFK1DEST_ONE;
1 = 1の場合、dest(pk、type)values(pk、type)にすべてを挿入します= 'one'の場合は、dest_one(pkfk、data)values(pk、content)にtype = 'two'にdest_two(dest_two( pkfk)values(pk)pk、type、utl_raw.cast_to_raw(content)select select in( 'one'、 'two');
Table dest_oneを変更する制約xfk1dest_one;
これは私が傾いている解決策です。私のBlobテーブルの外部キーを無効にすることは、私のテスト環境(10g -10.2.0.1.0)で機能させるように思われますが、非Blobテーブルの外部キーも無効にする必要があるかどうかはわかりません。 (9i、11g、または10gのその他のバージョンがどのように動作するかにより)。ここのリソースも大歓迎です。
本当にありがとう!
解決
別の解決策は、コミットまで制約評価を延期することです。マルチテーブルインサートが、あなたが期待して望むもの以外の順序で行を挿入していると思われます(ただしません)。次のように制約を再作成します。
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;
これにより、制約が延期され、作成された時から延期されるように制約が再現されます。次に、元の挿入をもう一度試してください。
共有して楽しんでください。