2

特定のソース列に基づいてテーブルのツリーに分割したい単一のテーブルがあります。複数列の挿入を使用してみたかったのですが、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)
 );

ソースには元のデータが含まれています。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');

前述のように、ここで外部キー制約違反が発生しました。ブロブが問題であったことをさらに説明するために、ブロブ挿入が機能していないが、ブロブ挿入が失敗したものを実現する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つは、複数の個別の挿入ステートメントに戻ることですが、ここで説明した方法とは異なり、サブテーブルの挿入を記述して、存在する行のみを挿入しようとする必要があるのではないかと心配しています。親の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がどのように動作するかによる)。ここのリソースもいただければ幸いです。

本当にありがとう!

4

1 に答える 1

2

別の解決策は、COMMITまで制約評価を延期することです。マルチテーブル挿入が、期待した順序とは異なる順序で行を挿入しているのではないかと思います(ただし、確かではありません)。次のように制約を再作成します。

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;

これにより、制約が再作成され、延期できるようになり、作成された時点から延期されます。次に、元のINSERTを再試行します。

共有してお楽しみください。

于 2010-11-11T18:05:31.107 に答える