0

sqlplus を呼び出すシェル スクリプトは次のとおりです。

#!/usr/bin/ksh

sqlplus $USER/$PASSWD@$DB<<!!>./logFile.log

SELECT 'IN sqlplus' FROM dual;

DECLARE tbl_xst integer;

SELECT COUNT(*) INTO tbl_xst FROM SYS.ALL_TABLES
WHERE table_name = 'SOME_TABLE'
AND OWNER = 'SOME_OWNER';

IF tbl_xst = 1 THEN
BEGIN
    DROP TABLE SOME_OWNER.SOME_TABLE;
END
END IF

SELECT 'The end' FROM dual;
!!

シェル スクリプトを実行してログ ファイル logFile.log を調べると、次のような内容が表示されます。

SQL*Plus: Release 10.2.0.3.0 - Production on Mon Oct 22 12:33:05 2012

Copyright (c) 1982, 2006, Oracle.  All Rights Reserved.


Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
With the Partitioning, Automatic Storage Management, OLAP, Data Mining
and Real Application Testing options

SQL> SQL>
'INSQLPLUS
----------
IN sqlplus

SQL> SQL>   2    3    4    5    6    7    8    9   10   11   12   13   14   15  Disconnected from Oracle Database 11g Enterprise Edition Releas
e 11.2.0.2.0 - 64bit Production
With the Partitioning, Automatic Storage Management, OLAP, Data Mining
and Real Application Testing options

ご覧のとおり、最初のロギング SELECT ステートメント ('IN sqlplus') は成功しますが、一番下の 2 番目のステートメントは成功しません。つまり、間にエラーがあるため、実行は到達しません。sqlplus がこのエラー メッセージをログ ファイルに書き込まないのはなぜですか?

いくつかのコメントの後に編集: sqlplus が指定されたログ ファイルに STDERR をダンプせず、STDOUT のみが記録されることが原因である可能性が最も高いことを確認しました。sqlplus コマンドをフォーマットして、両方のストリーム (STDOUT と ERR) を結合し、指定したログ ファイルに入れるにはどうすればよいですか? <<!!>ここで重要だと思います。

さらに実験した後に編集: 奇妙なことに、いくつかのエラー メッセージが STDOUT にダンプされています。不適切な DB オブジェクトを参照しようとする、適切に構文化されたものだと思います。SQL コンパイル エラーが発生した場合、明らかに STDERR に入ります。私がしたことは、上記の最初の SELECT と DECLARE の後に次の行を挿入することです。

DROP TABLE FAKE_NONEXISTING;

ステートメントは正当であり、コンパイルされますが、FAKE_NONEXISTING は存在せず、ログ ファイルに次のように表示されます。

SQL> SQL> DROP TABLE FAKE_NONEXISTING
           *
ERROR at line 1:
ORA-00942: table or view does not exist

ただし、ログ ファイルには、SQL コンパイル エラーと思われるものは何も記録されません。

4

2 に答える 2

1

stdoutSQL * Plusは、出力をとに分離しませんstderr。リダイレクトやシェルとは実際には何の関係もありません。そのコードをインタラクティブなSQL*Plusセッションに貼り付けた場合も、同じ問題が発生します。コンパイルして実行する必要のある完全なブロックを指定したことを通知していないため、コンパイルエラーは表示されません。

PL / SQLブロックを開始すると(この場合はでDECLARE)、その後に続くすべてのものは、SQL * Plusに現在のバッファを実行するように指示する終了.または/、を指定するまで、同じブロックの一部として扱われます。匿名ブロック全体。印刷する予定の2番目のプレーンは、不完全なブロックの一部として扱われるため、どちらも実行されません。スクリプトは、に遭遇する前に(で)終了しますselectThe end!!/、持っていないので、SQL*Plusは何も実行することを知りません。SQL * Plusに貼り付けた場合、同じ出力と15行目の入力を待機しているカーソルが表示されます。スクリプトバージョンはその時点で強制終了されます。これは、シェルスクリプトが入力を待機しているときにctrl-Cを押すのとほぼ同じです。

しかし、ブロックの他の重要な部分もいくつか欠けています。手続き型セクションと終了部分を追加BEGINして周囲に追加すると、エラーが表示されるようになります。エラーの一部は、セミコロンの欠落によるものです。これで始められるはずです:END/

#!/usr/bin/ksh

sqlplus $USER/$PASSWD@$DB<<!!>./logFile.log

SELECT 'IN sqlplus' FROM dual;

DECLARE -- start of PL/SQL block declaration
    tbl_xst integer;
BEGIN -- start of the actual block
    SELECT COUNT(*) INTO tbl_xst FROM SYS.ALL_TABLES
    WHERE table_name = 'SOME_TABLE'
    AND OWNER = 'SOME_OWNER';

    IF tbl_xst = 1 THEN
    BEGIN
        DROP TABLE SOME_OWNER.SOME_TABLE; -- this will error
    END; -- missing semi-colon, but separate BEGIN/END wrapper isn't really needed
    END IF; -- missing semi-colon
END; -- missing end to the block
/ - missing PL/SQL terminator/executor

-- now back in plain SQL mode
SELECT 'The end' FROM dual;
!!

これで、の周りのエラーが報告されるはずDROPです。これはDDLコマンドであり、PL/SQL内でそのように実行することはできません。次のような動的SQLを使用する必要があります。

    IF tbl_xst = 1 THEN
        EXECUTE IMMEDIATE 'DROP TABLE SOME_OWNER.SOME_TABLE';
    END IF;

(これはWilliam Stearnsが言及したことですが、テーブルを削除しようとしたときに発生するエラーをすべて飲み込むため、例外ブロックがないことを強くお勧めします。)WHEN OTHERSRAISE

ちなみに、SQL * Plusのバージョン、接続、およびプロンプト/行番号の情報を出力に表示したくない場合は、-s[ilent]オプションを使用してそれを抑制することができます。

于 2012-10-22T22:37:45.987 に答える
-2

エラー出力もログファイルにリダイレクトするには、次の行に 2>&1 を追加します。

sqlplus $USER/$PASSWD@$DB<<!!>./logFile.log 2>&1

私自身のコメントから更新されました...そして、>の代わりに>>を追加して、既存のファイルを追加して、ログを長期間使用できるようにします。

#!/usr/bin/ksh

sqlplus $USER/$PASSWD@$DB<<+EOF>>./logFile.log 2>&1

SELECT 'IN sqlplus' FROM dual;

BEGIN
    EXECUTE IMMEDIATE 'DROP TABLE SOME_OWNER.SOME_TABLE';
    EXCEPTION WHEN OTHERS THEN NULL;
END;

SELECT 'The end' FROM dual;
+EOF
于 2012-10-22T17:16:09.063 に答える