Sqlplusを使用して、シェルスクリプトのsqlファイルからクエリを挿入しようとしています。スキーマが正しくないため、一部のクエリが失敗する可能性があります。したがって、すべてのクエリが成功した場合にのみ、すべてのトランザクションをコミットしたいと思います。主な問題は、エラーに関係なくすべてのクエリを実行し、少なくとも1つのエラーが発生した場合はすべてのクエリをロールバックすることです。
すべてのクエリを実行する背後にある考え方は、エラーになるクエリを見つけて、そのためのスキーマ修正を作成することです。
私はこのコマンドを使用しています:
cat "temp.sql" | sqlplus -s sys/Oracle@xe as sysdba
ただし、sqlplusが終了すると、自動コミットされます。 11.1を使用しているため、set exitcommit off
を使用できません。
シェルスクリプトでこれを行う方法はありますか?
備考
ステートメントを発行します
cat "temp.sql" | sqlplus -s sys/Oracle@xe as sysdba
Sqlplusへのパイプは避けてください。実行する
sqlplus -s sys/Oracle @ xe as sysdba @ temp.sql
利点は、出力ファイルにプロンプトが生成されないことです。出力の外観をより適切に制御できます。一部の入力は、インタラクティブに作業する場合には意味のある結果を生成しますが、バッチジョブを実行する場合には意味がありません。コマンドをsqlplusにパイプすることに利点はありません。
SYSがトランザクションを読み取り専用に設定している場合でも、SYSによるクエリはトランザクション中に行われた変更を返します
DMLステートメントを発行する場合、これは動作ではありません。これにより、データが不整合になる可能性があります。
SQLデータベース操作言語(DML)コマンドのUPDATE、INSERT、およびDELETEを使用して、データベースに格納されている情報に加える変更を指定できます。これらのコマンドは、独立して、またはPL/SQLブロック内で使用できます。これらの変更は、SQL COMMITコマンド、SQLデータベース制御言語(DCL)コマンド、またはデータベース定義言語(DDL)コマンド(CREATE TABLEなど)を入力するか、自動コミット機能を使用するまで永続化されません。 SQL * Plusの自動コミット機能により、指定された数のSQL DMLトランザクションが成功した後に、保留中の変更がコミットされます。 (SQL DMLトランザクションは、UPDATE、INSERT、DELETEコマンド、またはPL/SQLブロックのいずれかです。)
そのため、すべてをロールバックできるように、スクリプトには適切なステートメントを含める必要があります。
SET EXITCOMMAND は11.2でSQL * Plusに導入されました。 SQL * Plusに本当に新しいものが追加されたとは思いません。 WHENEVERコマンドを使用して、SQL * Plusの動作を制御できます。
すべてのクエリが成功した場合にのみすべてのトランザクションをコミットしたい
したがって、最初のエラーが発生した場合、ロールバックして終了したいと思います。
したがって、スクリプトは WHENEVER SQLERROR ステートメントで開始する必要があります
WHENEVER SQLERROR EXIT FAILURE ROLLBACK
SQLエラーが発生した場合、トランザクションはロールバックされ、SQL * Plusが終了します。 SQL * Plusがエラーを通知するOSシステム依存の値であるというエラーコード
多分 WHENEVER OSERROR コマンドも実行する必要があります
WHENEVER OSERROR EXIT FAILURE ROLLBACK
もちろん [〜#〜] autocommit [〜#〜] は有効にすべきではありませんが、
SET AUTOCOMMIT OFF
がデフォルトであるため、このコマンドを実行しないでください。
これらのステートメントを サイトプロファイルまたはユーザープロファイルスクリプト(glogin.sqlまたはlogin.sql) に追加して、データベースに接続するたびに自動的に実行されるようにすることができます。
ここでは、スクリプトを実行する方法をドラフトします。
sqlplusスクリプトrun01.sql
SPOOL run01.log
REM file: run01.sql
WHENEVER SQLERROR EXIT FAILURE ROLLBACK
WHENEVER OSERROR EXIT FAILURE ROLLBACK
@temp.sql
SPOOL OFF
EXIT COMMIT
REM COMMIT is the default of EXIT
シェルスクリプトmain1.sh
#!/bin/bash
sqlplus $USER/$PASSWORD @run01.sql
if [[ $? = 0 ]]; then
echo "sql script executed successfully" >&
else
# alert
echo "error when executing sql script, check run01.log" >&2
fi
新しい要件を追加しました。
エラーに関係なくすべてのクエリを実行し、少なくとも1つのエラーが発生した場合はすべてのクエリをロールバックしたいと思います。
最初のエラーが発生した場合、スクリプトをロールバック終了出口で再度実行できます。その場合は、スクリプトを再度実行できますが、エラーが発生しても終了せず、スクリプトの実行を続行します。スクリプトの最後に、{EXIT COMMAND] 8 を使用してすべてのトランザクションをロールバックします。
sqlplusスクリプトrun02.sql
SPOOL run02.log
REM file: run02.sql
WHENEVER SQLERROR CONTINUE NONE
WHENEVER OSERROR EXIT FAILURE ROLLBACK
@temp.sql
SPOOL OFF
EXIT ROLLBACK
シェルスクリプトmain2.sh
#!/bin/bash
sqlplus $USER/$PASSWORD @run01.sql
if [[ $? = 0 ]]; then
echo "sql script executed successfully" >&
else
sqlplus $USER/$PASSWORD @run02.sql
# alert
echo "error when executing sql script, check run02.log" >&2
fi
これが私の推奨するソリューションです。目に見える唯一の欠点は、最初のエラーが発生するまで実行されるtemp.sqlスクリプトのステートメントが、スクリプトrun01.sqlとスクリプトrun02.sqlの2回実行されることです。 Linux環境では、スクリプト全体を実行してgrep
ステートメントでログファイルを分析し、この分析の結果に応じてコミットまたはロールバックでセッションを終了することで、これを回避することができます。
sqlplusスクリプトrun03.sql
SPOOL run03.log
REM file: run03.sql
WHENEVER SQLERROR CONTINUE NONE
WHENEVER OSERROR EXIT FAILURE ROLLBACK
@temp.sql
SPOOL OFF
Host ./analyze_logfile.sh
@exit.sql
シェルスクリプトmain3.sh
#!/bin/bash
sqlplus $USER/$PASSWORD @run03.sql
if [[ $? = 0 ]]; then
echo "sql script executed successfully" >&
else
# alert
echo "error when executing sql script, check run03.log" >&2
fi
シェルスクリプトanalyze_logfile.sh
#/bin/bash
# file: analyze_logfile.sh
if grep "^ORA-" run03.log; then
echo "EXIT ROLLBACK"
else
echo "EXIT COMMIT"