アプリ版:「スタンプのみでお礼する」機能のリリースについて

SQL*Loaderを使ってデータをインポートするのですが、既存データが存在するテーブルにインポートするため、実行前に、条件に一致する一部のデータを削除します。

ですが、SQL*Loaderでインポートが失敗した際には、元に戻したいと思っています。

そういう場合に、SQL*PlusからDELETEのSQL文を実行してから、SQL*Loaderを起動してインポートするとなると、SQL*Plusから抜けた時点でCOMMITされてしまいますよね?そのためSQL*LoaderでインポートがエラーになってROLLBACKされても、削除されたデータは元に戻らないですよね・・・。

全件削除なら、CTLファイル内でREPLACEを指定してインポートするのですが・・・

データの一部削除とSQL*Loaderでのインポートを一連の処理として、エラーの際にはROLLBACKさせられる方法はありますでしょうか?

よろしくお願いします。

A 回答 (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もできなくなるため)
    • good
    • 0
この回答へのお礼

緊急で質問していたにも関わらず、お返事が大変遅れまして申し訳ありません。
(当日以降、お返事ができない環境になってしまいました)

> SQL*Loaderはデフォルトではある程度の単位で勝手にcommitが切られてしまう

というのも知りませんでした・・・。

> VIEWにinsteadトリガを定義しておいてからVIEW目掛けてSQL*loaderでINSERTを行うことになります

というのが、一番本来の目的(LoaderでのエラーでRollbackしたい、或いはLoaderでのデータインポートの際にUpdateのような形をとりたい)に叶っている気が致します。

お返事、本当にありがとうございました!

お礼日時:2005/12/21 09:00

別表への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を空にして終わりと
なります。

性能の面などの問題などもありますがいかがでしょうか?
    • good
    • 0
この回答へのお礼

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

検討したいと思います。
ありがとうございました。

お礼日時:2005/12/14 18:20

こんにちは。


具体的な方法は思いついていなくて申し訳ないのですけども
SQL*Loaderの代わりに外部表を使用し、SQL文によるデータの参照と
インポートを行う事で、一連の処理をROLLBACKする事ができないですかね?

9i以降限定&インポート時のエラー処理が思い浮かばず…。
ごめんなさい、ゴミレスでした。
    • good
    • 0
この回答へのお礼

そう言えば、環境も書いてなかったですね・・・(Window2000で9iです)

SQL*Loaderでのインポートのみであれば、エラー発生時にはCommitされない?と思うので、問題ないのですが・・・
やはり他の方が言われるように、ビューや事前のExportなど、「Rollback」できる環境を別途考える必要があるようですね(^^)

お返事ありがとうございました。

お礼日時:2005/12/14 18:19

もしかして



如何なる時でも、テーブルは新・旧いずれかの参照が出来る。
新を参照するのは、全件正常の場合のみ。

というのを考えているのですか?

そうであるなら、REPLACEを指定する方法では無理です。
#1で書かれた方法では無理です。

考えやすいのは、2つのテーブルとビュー(またはシノニム)を使う方法でしょうか。
・テーブルを2つ用意する(例えば、AとB)
・SQL*LOADERで、Bへロードする。
・ロード正常なら、ビューの参照先をAからBへ変更。

次回のロードでは
・SQL*LOADERで、Aへロードする。
・ロード正常なら、ビューの参照先をBからAへ変更。

参照する人は、ビューを参照する。

ビューの定義を切り替える瞬間だけが微妙ですが、
基本的にDMLでなく、DDL側が弾かれるハズですので
大丈夫でしょう。
注意がいるとすれば、ビューに依存するようなストアドやビューは、
切り替えの瞬間に、invalid状態になり、リコンパイルが必要に
なります。
ストアドなら、どちらを参照すべきか考えて、テーブルを見るようにすれば良いと思います。
依存ビューもやめることは可能だと思いますし、そのビュー定義を同時に変更しても
良いと思います。
    • good
    • 0
この回答へのお礼

ビューを使う方法もあったのですね・・・
やはり一連の処理の中でRollbackというのは無理なのですよね(^^;

> もしかして
> 如何なる時でも、テーブルは新・旧いずれかの参照が出来る。
> 新を参照するのは、全件正常の場合のみ。
> というのを考えているのですか?

という意味がちょっと分からなかったのですが、イメージ的には「失敗したからRollbak」というように、「処理をなかったことにする」ということが可能かどうか・・・と思っていました。

頂いた回答を参考にして、他の処理を追加することで対応していきたいと思います。

ありがとうございました。

お礼日時:2005/12/14 18:16

SQL*Loaderで失敗した際、データを元に戻す為にはLoad前にデータをExportし、その後SQL*Loaderでデータをロード。

その後、失敗していた場合、ExportしたデータをImportすればROLLBACKもどきになります。

SQL*Loaderが失敗した時の判断ですが、使用しているOSがWindowsであれば、ERRORLEVELが取得できると思うので、それを利用するのが良いかと思います。

その他のOSは良くわかりませんので、SQL*LoaderのマニュアルとOSのマニュアルを見てバッチなりスクリプトを作成してください。
    • good
    • 0
この回答へのお礼

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

お礼日時:2005/12/14 18:10

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

関連するカテゴリからQ&Aを探す