Java Hibernate/JPAを使用するEEアプリケーションを開発しています。使用したいデータの一部は、5つのOracleテーブルに定期的に(再)ロードする必要がある別のビジネスユニットのスプレッドシートから取得しています、既存のデータを上書きします。5つのsql * loader制御ファイルを開始するシェルスクリプトを使用しています。Excelファイルは正規化されていないため、各制御ファイルはスキップするフィラーフィールドを指定しています。
OPTIONS(skip=2)
load data
REPLACE
--#########################################
into table TABLE_NAME
fields terminated by "," optionally enclosed by '"'
TRAILING NULLCOLS
(
ACCOUNT_ID ,
REST_STOP_ID ,
DESCRIPTION FILLER ,
GROUP FILLER ,
FUNCTION ,
JOB_ID "substr(:JOB_ID, 0, INSTR(:JOB_ID,' - ',1))",
<35 other fields>
etc...
SQL * Loaderとこのスプレッドシートからのcsvファイルを使用して、このデータを空のテーブルに初めてインポートすると正常に機能します。しかし、その後、いずれかの制御ファイルオプションが原因で、その後の実行sql * loaderが失敗します。
rEPLACEを使用する場合:
SQL*Loader-926: OCI error while executing delete/truncate (due to REPLACE/TRUNCATE keyword)
**ORA-02292:** integrity constraint (SCHEMA.FK5BA979794B0A176A) violated - child record found
tRUNCATEを使用する場合:
SQL*Loader-926: OCI error while executing delete/truncate (due to REPLACE/TRUNCATE keyword)
**ORA-02266:** unique/primary keys in table referenced by enabled foreign keys
また、どのテーブルにデータが入力されるかを並べ替えようとしましたが、うまくいきませんでした。
また、制約を無効にしてみました
ALTER TABLE TABLE_NAME DISABLE CONSTRAINT SYS_C0090398
ORA-02297: cannot disable constraint (SCHEMA.SYS_C0090398) - dependencies exist
(0 rows affected)
これまでの私の回避策は、すべてのテーブルを削除してアプリケーションを再起動し、Hibernateで5つのテーブルを再作成してから、sql * loaderスクリプトを実行することです。今は開発中なので大したことはありません。しかし、本番環境に入ると、再起動してテーブルを作成し続けることができません。実際にプロダクションに行くと、Hibernateの外でテーブルを作成しますが、今は永続化オプションhibernate.hbm2ddl.auto
をupdate
に設定します。
これらの5つのテーブルにcsv/Excelファイルで提供されたデータを定期的に再入力するエレガントな(半)自動ソリューションを探しています。
再利用可能なデータロードでは、CSVファイルから読み取る静的外部テーブルを定義することをお勧めします。ファイルを読み取るには、Oracle DIRECTORY
オブジェクトが必要です。
この例では、FOO_TAB
ディレクトリからFOO_TAB.CSV
ファイルを読み取るFOO_DIR
という5列の外部テーブルを作成します。
CREATE TABLE foo_tab
(
a1 VARCHAR2(4000),
a2 VARCHAR2(4000),
a3 VARCHAR2(4000),
a4 VARCHAR2(4000),
a5 VARCHAR2(4000),
)
ORGANIZATION EXTERNAL
(
TYPE Oracle_LOADER
DEFAULT DIRECTORY foo_dir
ACCESS PARAMETERS
(
RECORDS DELIMITED BY newline
BADFILE 'foo_tab.bad'
DISCARDFILE 'foo_tab.dis'
LOGFILE 'foo_tab.log'
SKIP 1 /* first row just has column headers */
FIELDS TERMINATED BY "," OPTIONALLY ENCLOSED BY '"'
LTRIM
MISSING FIELD VALUES ARE NULL
(
a1 CHAR(4000),
a2 CHAR(4000),
a3 CHAR(4000),
a4 CHAR(4000),
a5 CHAR(4000),
)
)
LOCATION (foo_dir:'foo_tab.csv')
)
REJECT LIMIT UNLIMITED;
唯一の方法は、ローダーを実行する前に参照制約を無効にすることです。その後、それらを有効にします-新しいデータが一貫していることを願っています。
SQLローダー内で参照整合性を無効にするオプションはありません。参照整合性により、直接ロード方式を使用できなくなります。
ロードする前に参照制約を無効にしてから再度有効にすることを検討しましたか?
最良の方法は、参照制約に従って(制約を無効にするかどうかにかかわらず)順次ロードすることです。
例
ここで、child_tab_fk1は、親テーブル、parent_tabに関連付けられた外部キー制約になります。
制約を無効にする
ALTER TABLE parent_tab DISABLE CONSTRAINT pk_parent;
ALTER TABLE child_tab DISABLE CONSTRAINT child_tab_fk1;
参照制約のない親テーブルparent_tabをロードします
親テーブルparent_tabへの参照制約を持つ子テーブルchild_tabをロードします。
制約を有効にする
ALTER TABLE parent_tab ENABLE CONSTRAINT pk_parent;
ALTER TABLE child_tab ENABLE CONSTRAINT child_tab_fk1;
補遺
これらのテーブルのロードをシーケンスしようとしたときに参照制約エラーが引き続きスローされる場合、これは、テーブルのロードシーケンスがまだ正確ではないことを意味します(参照整合性の参照)。
また、直接ロードは、有効な参照制約と互換性がありません(ここを参照 ドキュメント )。したがって、おそらく、直接ロードで参照制約を無効にすることを省略したでしょう。
まず、親テーブルに外部キー制約がないことから始めて、徐々にテーブルをアプローチに追加します(テーブルに外部キーがない場合、参照制約エラーをスローするのは非常に困難です)。
次に、外部キー制約を手続き的に無効化/有効化することを検討し、このアクティビティがこのchronジョブの前後に発生するようにスケジュールします。