web-dev-qa-db-ja.com

シェルスクリプトでsqlplusセッションを保持する方法

Sqlplusを使用して、シェルスクリプトのsqlファイルからクエリを挿入しようとしています。スキーマが正しくないため、一部のクエリが失敗する可能性があります。したがって、すべてのクエリが成功した場合にのみ、すべてのトランザクションをコミットしたいと思います。主な問題は、エラーに関係なくすべてのクエリを実行し、少なくとも1つのエラーが発生した場合はすべてのクエリをロールバックすることです。

すべてのクエリを実行する背後にある考え方は、エラーになるクエリを見つけて、そのためのスキーマ修正を作成することです。

私はこのコマンドを使用しています:

cat "temp.sql" | sqlplus -s sys/Oracle@xe as sysdba  

ただし、sqlplusが終了すると、自動コミットされます。 11.1を使用しているため、set exitcommit offを使用できません。

シェルスクリプトでこれを行う方法はありますか?

1
cppcoder

備考

ステートメントを発行します

 cat "temp.sql" | sqlplus -s sys/Oracle@xe as sysdba  
  1. Sqlplusへのパイプは避けてください。実行する

    sqlplus -s sys/Oracle @ xe as sysdba @ temp.sql

利点は、出力ファイルにプロンプ​​トが生成されないことです。出力の外観をより適切に制御できます。一部の入力は、インタラクティブに作業する場合には意味のある結果を生成しますが、バッチジョブを実行する場合には意味がありません。コマンドをsqlplusにパイプすることに利点はありません。

  1. SYSを使用して、アプリケーションオブジェクトとアプリケーションデータを操作しないでください。セキュリティ上の理由はたくさんあります。その上、あなたはそれに気づくべきです

SYSがトランザクションを読み取り専用に設定している場合でも、SYSによるクエリはトランザクション中に行われた変更を返します

DMLステートメントを発行する場合、これは動作ではありません。これにより、データが不整合になる可能性があります。

  1. manual :から

    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"
3
miracle173