4

私は SQL Server ユーザーであり、Oracle を使用して行う小さなプロジェクトがあるため、Oracle の特殊性のいくつかを理解しようとしています。次の状況をよりよく理解するには、助けが必要だと思います。

作成する前に一時テーブルが存在するかどうかをテストしたいので、ここに次のコードを用意しました。

DECLARE
  table_count INTEGER;
  var_sql VARCHAR2(1000) := 'create GLOBAL TEMPORARY table TEST (
            hello varchar(1000) NOT NULL)';
BEGIN
  SELECT COUNT(*) INTO table_count FROM all_tables WHERE table_name = 'TEST';

  IF table_count = 0 THEN
    EXECUTE IMMEDIATE var_sql;
  END IF;
END;

正常に動作するので、一度実行した後、IF に else ステートメントを追加しました。

ELSE
  insert into test (hello) values ('hi');

もう一度実行すると、テストテーブルに行が追加されました。

OK、コードの準備ができて機能していたので、一時テーブルを削除してステートメント全体を再度実行しようとしましたが、実行すると次のエラーが発生します。

ORA-06550: line 11, column 19:
PL/SQL: ORA-00942: table or view does not exist
ORA-06550: line 11, column 7:
PL/SQL: SQL Statement ignored
06550. 00000 -  "line %s, column %s:\n%s"
*Cause:    Usually a PL/SQL compilation error.
*Action:

次に、else ステートメントを次のように変更したところ、再び機能するようになりました。

ELSE
  EXECUTE IMMEDIATE 'insert into test (hello) values (''hi'')';

私の質問は、個別に実行するのに、EXECUTE IMMEDIATE の代わりに単純に挿入を使用できる理由と、BEGIN の直後の SELECT ステートメントが機能するのに、残りのすべてが EXECUTE IMMEDIATE を正しく実行する必要があるように見える理由です。

4

3 に答える 3

7

PL/SQL ブロック全体がコンパイル時に解析されますが、動的ステートメント内のテキストは実行時まで評価されません。(それらは匿名ブロックの場合とほぼ同じですが、それでも異なる手順です)。

if/else も実行時まで評価されません。コンパイラは、挿入を行うまでにテーブルが常に存在することを認識していません。ブロック全体を解析する時点でテーブルが存在するかどうかのみを確認できます。

テーブルが既に存在する場合は問題ありません。コンパイラはそれを見ることができ、ブロックが実行され、select が 1 を取得し、else に入って挿入を行います。しかし、存在しない場合、挿入の解析はコンパイル時に ORA-00942 で正しく失敗し、ブロック内の何も実行されません。

テーブルの作成は動的であるため、テーブルへのすべての参照も動的である必要があります。基本的に、コードが読みにくくなり、構文エラーを隠すことができます。動的コードは実行時まで解析されないためです。長い時間。

とにかく、グローバル一時テーブルはオンザフライで作成しないでください。これらは、各セッションに固有の一時データを持つ永続的なオブジェクトであり、アプリケーション コードの一部として作成/削除しないでください。(通常、アプリケーションでスキーマの変更を行うべきではありません。エラー、データ損失、予期しない副作用を避けるために、アップグレード/メンテナンスの変更に限定して制御する必要があります。GTT も例外ではありません)。

他のリレーショナル データベースの一時テーブルとは異なり、Oracle データベースで一時テーブルを作成する場合は、静的テーブル定義を作成します。一時テーブルは、データ ディクショナリに記述されている永続オブジェクトですが、セッションがテーブルにデータを挿入するまでは空に見えます。すべての PL/SQL ストアド プロシージャに対してではなく、データベース自体に対して一時テーブルを作成します。

GTT を一度作成し、すべての PL/SQL コードを静的にします。SQL Server のローカル一時テーブルに近いものが必要な場合は、PL/SQL コレクションを調べてください。

于 2015-11-10T11:45:34.190 に答える