• ベストアンサー

データ削除とSQL*Loaderでのインポート

SQL*Loaderを使ってデータをインポートするのですが、既存データが存在するテーブルにインポートするため、実行前に、条件に一致する一部のデータを削除します。 ですが、SQL*Loaderでインポートが失敗した際には、元に戻したいと思っています。 そういう場合に、SQL*PlusからDELETEのSQL文を実行してから、SQL*Loaderを起動してインポートするとなると、SQL*Plusから抜けた時点でCOMMITされてしまいますよね?そのためSQL*LoaderでインポートがエラーになってROLLBACKされても、削除されたデータは元に戻らないですよね・・・。 全件削除なら、CTLファイル内でREPLACEを指定してインポートするのですが・・・ データの一部削除とSQL*Loaderでのインポートを一連の処理として、エラーの際にはROLLBACKさせられる方法はありますでしょうか? よろしくお願いします。

  • Oracle
  • 回答数5
  • ありがとう数6

質問者が選んだベストアンサー

  • ベストアンサー
回答No.5

一つ言い忘れていたので... MERGE文は9iからの機能ですので、もし8や8iをお使いであれば使用できません。 MERGEを使わない方法としてはinsteadトリガと呼ばれるものがあります。 トリガには beforeトリガ(実行前に自動的に実行) afterトリガ(実行後に自動的に実行) logonトリガ(ログオン直後に自動的に実行) など色々ありますが insteadトリガは(実行内容の変わりにトリガのみを実行)という機能になります。 今回のトリガの内容までは詳しく記述しませんがinsertが来たら既存行と一致するかしないかによって 代わりにupdateを実行するかinsertを実行するかを振り分けれます。 insteadトリガを使うときに気をつけなければいけないのは VIEWにしか定義できないことと(必然的に本来挿入をしたい表を参照するVIEWを作成し、 そのVIEWにinsteadトリガを定義しておいてからVIEW目掛けてSQL*loaderでINSERTを行うことになります。) SQL*Loaderはデフォルトではある程度の単位で勝手にcommitが切られてしまうので bindsizeやrowsといったSQL*Loaderのパラメータを大きめに設定してやる必要があります。 (途中でcommitを切ってしまっていると挿入の途中で失敗してしまった場合中途半端な 状態でcommitされてしまい、rollbackもできなくなるため)

sky_blue
質問者

お礼

緊急で質問していたにも関わらず、お返事が大変遅れまして申し訳ありません。 (当日以降、お返事ができない環境になってしまいました) > SQL*Loaderはデフォルトではある程度の単位で勝手にcommitが切られてしまう というのも知りませんでした・・・。 > VIEWにinsteadトリガを定義しておいてからVIEW目掛けてSQL*loaderでINSERTを行うことになります というのが、一番本来の目的(LoaderでのエラーでRollbackしたい、或いはLoaderでのデータインポートの際にUpdateのような形をとりたい)に叶っている気が致します。 お返事、本当にありがとうございました!

その他の回答 (4)

回答No.4

別表へのSQL*LoaderでのINSERT+ MERGE文で解決できないでしょうか。 まず、本来の表と全く同じ定義の空の表を create table temp_table as select * from moto_table; で作成し、そこにSQL*LoaderでINSERTします。 SQL*LoaderによるINSERTが失敗すればtemp_tableを空にして失敗で終わりです。 成功すれば次に以下のようなMERGE文で merge into moto_table m using temp_table t on (e.id = t.id) when matched then update set e.comment=t.comment when not matched then insert (id,comment) values(id,comment); (id列が一致すればcomment列を上書き、一致しなければINSERT) 1トランザクションにてtemp_tableからmoto_table へデータを更新または挿入します。 成功すればcommitすれば良いですし、失敗すれば自動的にROLLBACKされた後、 SQL*Loaderの時と同様にtemp_tableを空にして終わりと なります。 性能の面などの問題などもありますがいかがでしょうか?

sky_blue
質問者

お礼

Margeというのは初めて知りました・・・ なるほど、空の状態でインポートしておいて、そこに「元からあるもので、インポートされていないデータを追加する」ということですね! 検討したいと思います。 ありがとうございました。

noname#87380
noname#87380
回答No.3

こんにちは。 具体的な方法は思いついていなくて申し訳ないのですけども SQL*Loaderの代わりに外部表を使用し、SQL文によるデータの参照と インポートを行う事で、一連の処理をROLLBACKする事ができないですかね? 9i以降限定&インポート時のエラー処理が思い浮かばず…。 ごめんなさい、ゴミレスでした。

sky_blue
質問者

お礼

そう言えば、環境も書いてなかったですね・・・(Window2000で9iです) SQL*Loaderでのインポートのみであれば、エラー発生時にはCommitされない?と思うので、問題ないのですが・・・ やはり他の方が言われるように、ビューや事前のExportなど、「Rollback」できる環境を別途考える必要があるようですね(^^) お返事ありがとうございました。

回答No.2

もしかして 如何なる時でも、テーブルは新・旧いずれかの参照が出来る。 新を参照するのは、全件正常の場合のみ。 というのを考えているのですか? そうであるなら、REPLACEを指定する方法では無理です。 #1で書かれた方法では無理です。 考えやすいのは、2つのテーブルとビュー(またはシノニム)を使う方法でしょうか。 ・テーブルを2つ用意する(例えば、AとB) ・SQL*LOADERで、Bへロードする。 ・ロード正常なら、ビューの参照先をAからBへ変更。 次回のロードでは ・SQL*LOADERで、Aへロードする。 ・ロード正常なら、ビューの参照先をBからAへ変更。 参照する人は、ビューを参照する。 ビューの定義を切り替える瞬間だけが微妙ですが、 基本的にDMLでなく、DDL側が弾かれるハズですので 大丈夫でしょう。 注意がいるとすれば、ビューに依存するようなストアドやビューは、 切り替えの瞬間に、invalid状態になり、リコンパイルが必要に なります。 ストアドなら、どちらを参照すべきか考えて、テーブルを見るようにすれば良いと思います。 依存ビューもやめることは可能だと思いますし、そのビュー定義を同時に変更しても 良いと思います。

sky_blue
質問者

お礼

ビューを使う方法もあったのですね・・・ やはり一連の処理の中でRollbackというのは無理なのですよね(^^; > もしかして > 如何なる時でも、テーブルは新・旧いずれかの参照が出来る。 > 新を参照するのは、全件正常の場合のみ。 > というのを考えているのですか? という意味がちょっと分からなかったのですが、イメージ的には「失敗したからRollbak」というように、「処理をなかったことにする」ということが可能かどうか・・・と思っていました。 頂いた回答を参考にして、他の処理を追加することで対応していきたいと思います。 ありがとうございました。

  • nnfuji
  • ベストアンサー率28% (200/701)
回答No.1

SQL*Loaderで失敗した際、データを元に戻す為にはLoad前にデータをExportし、その後SQL*Loaderでデータをロード。その後、失敗していた場合、ExportしたデータをImportすればROLLBACKもどきになります。 SQL*Loaderが失敗した時の判断ですが、使用しているOSがWindowsであれば、ERRORLEVELが取得できると思うので、それを利用するのが良いかと思います。 その他のOSは良くわかりませんので、SQL*LoaderのマニュアルとOSのマニュアルを見てバッチなりスクリプトを作成してください。

sky_blue
質問者

お礼

なるほど・・・Exportしておいて元に戻すという方法がありますよね。 ありがとうございました!

関連するQ&A

  • SQL*Loaderでのデータロード

    SQL*Loaderでデータロードを実行するとき ロードするテキストファイルのある列の部分が スペースのとき、テーブルで設定したデフォルト値 をロードさせたいのですが、どうCTLファイルで記述 すればよいのですか? 教えてください。おねがいします。

  • SQL-Loaderが動かないです。

    みなさんこんにちは 作成されたデータをSQL-Loaderにてオラクルデータベースに取込み を行います。 下記にソースを書きましたが、まずTEST.batファイルを実行し、 TEST.bat側からTEST.ctlを実行し、TEST_WORKテーブルにデータを 格納します。 *****TEST.batの内容***** SQLLDR USERID=TEST1/TEST1@GUEST CONTROL=TEST.ctl LOG=LOG.txt ************************ *****TEST.ctlの内容***** LOAD DATA INFILE 'D:\test1.dat' TRUNCATE PRESERVE BLANKS INTO TABLE TEST_WORK FIELDS TERMINATED BY "|" TRAILING NULLCOLS (KOUMOKU1, KOUMOKU2, KOUMOKU3, KOUMOKU4) ************************ 実際にこれを実行した所、問題なく正常終了しました。 しかし、これをホスト側からFTPにて実行を行うと、 TEST.batが実行されません。もちろんログも出力されません。 ファイルが実行できてないので、ファイルのコピーを行う簡単 なバッチファイルを作成し、ホスト側から実行を行ってもらった 場合、こちらは問題ありませんでした。 となると、SQL-Loaderのソースに何か問題があるのでは?と 思いますが・・・色んなサイトでLoaderのソースを拝見しましたが、 見当がつかないです。 ソースを見て、気になる点や、同じ経験をされた方いらっしゃい ましたら、お知恵をお貸しください。 ちなみに、SQL-Loaderを実行するマシンのOSはWindows2000Proです。 よろしくお願いします。

  • sql*loader 数値のロード

    SQL*LOADERにて NUMBER(3,0)のフィールドに、小数点以下を含む数値をもったデータをロードすると 四捨五入か何かされて整数でデータがロードされてしまいます。 テーブル、CTLファイル、csvレコード、登録結果は以下のとおりです。 テーブル: CREATE TABLE tbl1 ( CLM001 NUMBER(3,0) NOT NULL, CLM002 VARCHAR2(30) ) CTLファイル: LOAD DATA INFILE 'tbl1.csv' BADFILE 'tbl1.bad' TRUNCATE INTO TABLE tbl1 FIELDS TERMINATED BY ',' TRAILING NULLCOLS ( CLM001, CLM002 ) csvレコード: 0.9,aaaaa 3.1,bbbbb 登録結果(SQL*LOADER実行結果): 1,aaaaa 3,bbbbb 小数点を含むデータをロード時にエラーとしたいのですが、何かいい方法ありますでしょうか? 環境はSQL*Loader: Release 9.2.0.1.0になります。

  • SQL*Loaderで既存のレコードの更新

    SQL*Loaderで既存のレコードがあったらUpdate処理を行いたいのですが 「Oracle7 Server ユーティリティ」に SQL*Loaderは、既存レコードがNULL列であったとしてもレコードを更新しません。 既存の行を更新するには、次の手順を利用してください。 1.データを一時表にロードする 2.相関副問合わせを持つSQL言語のUPDATE文を使用する 3.一時表を削除する とありますが、上記の1~3が具体的にどうすれば良いのか分りません・・・ 1.データとは、テーブルのデータ?それともロードファイルのデータ??   3.に削除とあるので、作成するのでしょうか?? 2・これはctlファイルに記述するでいいのでしょうか?? 記述の仕方は?? 3.ドロップコマンドはctlに記述でよろしいのでしょうか?? などなど・・ すみません、ご教授お願いできませんか??

  • SQL*Loaderでのゼロ埋め

    SQL*Loaderでデータを取り込む際に、対象データの左桁をゼロ埋めにする方法を教えてください。 例えば、取り込み対象の項目が、5桁未満の場合はゼロ埋めを行う。 ・取り込み対象:111 ・ゼロ埋め後の結果:00111(この値を取り込む) 上記を実装する方法が分からず困っております。 SQL*Loaderは初めて使用するため、調べる方法も見つけられませんでした。 何か良い方法がありましたら、お教え願えないでしょうか。 また、上記を実装するための参考になるサイト等を教えていただけないでしょうか。 よろしく御願い致します。

  • SQL Loaderを使いたい

    Oracleのバージョンは8、自分のPCには Oracle8Client(Application User) がインストールされています。 見よう見まねで制御ファイルを記述し、バッチファイルを作成したところ、 ( sqlldr USERNAME/PASSWORD@SID control= test.ctl ) コマンドプロンプトには以下のように表示されました。 「C:\SQL>sqlldr USERNAME/PASSWORD@SID control = test.ctl 'sqlldr' は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチファイルとして認識されていません。」 実行できない原因はどこにあるか教えてください。 1.そもそもSQL Loaderを利用できる環境になっていない (そのままでは使えなくて何かしら設定が必要とか) 2.コマンドがまちがっている (test.ctlのパスを記述しないとだめとか、SIDは要らないだとか) 3.制御ファイルがまちがっている どの可能性が一番高いでしょうか?

  • oracleデータのインポート&エクスポートについて

    oracleデータをインポートするにはSQL*LOADERを使用するのが一般的な方法の一つですが、 同じように、その逆であるエクスポートを行う場合はどのような手段を用いますか? 条件としては ・バッチ(シェル)で実行できる事。 ・SQL*LOADERでインポートする為のデータと互換性のあるフォーマット(CSV)である事。 ・ツールの追加購入は考えていません。

  • SQL*Loaderで「オブジェクトが存在しない」というエラーが出ます

    SQL*Loaderでデータをインサートしたいのですが、 オブジェクトがあるのに、 「SQL*Loader-941: 表~の記述中にエラーが発生しました。 ORA-04043: オブジェクト~は存在しません。」というエラーが出力されます。 何が原因なのでしょうか? すみませんが教えて下さい!お願いします!

  • SQL*Loaderについて

    SQL*Loaderを用いてOracleのテーブルにデータを格納 しようと思っています。 格納するデータはテキストファイルです。 しかし、NUMBER型にマイナスのデータ(-123.45)を格納 するとエラーになってしまいます。 原因としては、多分テキストデータの表示が"123.45-"と なっているからだと思います。 "123.45-"の表示でエラーとならずに"-123.45"と格納 されるようにすることは不可能なのでしょうか? 現在作成のLoaderは下記になっています。 load data truncate into table DEPT fields terminated by X'09' trailing nullcols (DEPTNO ,POSTNO NULLIF POSTNO=BLANKS ,SAL NULLIF SAL=BLANKS ) ちなみにSALがNUMBER型の項目です。

  • SQL*Loaderについて2

    SQL*Loaderを用いてOracleのテーブルにデータを格納しようと思っています。 格納するデータはテキストファイルです。 テキストファイルのデータはカンマ区切りになっているのですが、エラーとなってしまいます。 このテキストファイルをタブ区切りにすれば問題なく動くのですが、カンマ区切りでは無理 なのでしょうか? 現在作成のLoaderは下記になっています。 load data truncate into table DEPT fields terminated by X'09' trailing nullcols (DEPTNO ,POSTNO NULLIF POSTNO=BLANKS ,SAL NULLIF SAL=BLANKS ) 現在のデータは下記になっています。 1001,1234567,100000 1002,1234567,200000