Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SQL Anywhere 12.0.1 » SQL Anywhere サーバー SQL の使用法 » ストアドプロシージャー、トリガー、バッチ、ユーザー定義関数

 

プロシージャー、トリガー、ユーザー定義関数、バッチで使用される EXECUTE IMMEDIATE

EXECUTE IMMEDIATE 文を使うと、文字列 (引用符で囲む) と変数を使って文を組み立てることができます。次に示すのは、テーブルを作成する EXECUTE IMMEDIATE 文を含むプロシージャーの例です。

CREATE PROCEDURE CreateTableProcedure(
      IN tablename CHAR(128) )
BEGIN
   EXECUTE IMMEDIATE 'CREATE TABLE '
   || tablename
   || '( column1 INT PRIMARY KEY )'
END;

EXECUTE IMMEDIATE 文は、結果セットを返すクエリで使用できます。文が結果セットを返すように指定するために、EXECUTE IMMEDIATE 文で WITH RESULT SET ON 句を使用します。デフォルトの動作では、文は結果セットを返しません。WITH RESULT SET ON または WITH RESULT SET OFF を指定することは、プロシージャーが作成されるときだけではなく、プロシージャーが実行されるときの動作についても影響をもたらすことになります。

次のプロシージャーを考えてみます。

CREATE OR REPLACE PROCEDURE test_result_clause()
BEGIN
    EXECUTE IMMEDIATE WITH RESULT SET OFF 'SELECT 1';
END;

プロシージャー定義に RESULT SET 句が含まれていないと、データベースサーバー側ではプロシージャーによって結果セットが生成されるのかどうかを判断しようとします。ここでは、EXECUTE IMMEDIATE 文では、結果セットを生成しないように設定されています。そのため、データベースサーバー側では、プロシージャーには結果セットのカラムがないと判断されるため、このプロシージャーの SYSPROCPARM システムビューにはカラムが表示されません。このプロシージャーの呼び出しに DESCRIBE を指定しても、結果カラムは返されません。カーソルを開いたり、文を実行するかどうかを決定するために、Embedded SQL アプリケーションによってこの情報が使用された場合には、文が実行されて、エラーが返されます。

2 番目の例では、上記のプロシージャーの修正バージョンを考えてみます。

CREATE OR REPLACE PROCEDURE test_result_clause()
BEGIN
    EXECUTE IMMEDIATE WITH RESULT SET ON 'SELECT 1';
END;

ここでは、WITH RESULT SET ON 句が指定されているため、SYSPROCPARM システムビューにはこのプロシージャーのローが存在しています。プロシージャーが EXECUTE IMMEDIATE を使用しているため、データベースサーバー側では、実際に結果セットがどのようになるかついては把握できません。ただし、結果セットが存在することは予測できるため、データベースサーバーは SYSPROCPARM に、expression という名前の SMALLINT 型のダミーの結果セットのカラムを定義することによって、結果セットに対応していることを示します。作成される結果セット用ダミーカラムが 1 つ だけであることに注意してください。サーバー側では、EXECUTE IMMEDIATE 文が使用されているときに、各結果セットのカラム数や型については判断できません。そのため、さらに少し修正したバージョンの例を考えてみます。

CREATE OR REPLACE PROCEDURE test_result_clause()
BEGIN
    EXECUTE IMMEDIATE WITH RESULT SET ON 'SELECT 1, 2, 3';
END;

ここでは、SELECT 文は 3 つのカラムの結果セットを返しますが、サーバーの SYSPROCPARM システムビューには、1 つのローがあるだけです。そこで、次のクエリを見てください。

SELECT * FROM test_result_clause();

このクエリは、SQLCODE -866 エラーになります。これは、実行時の結果セットの定義が SYSPROCPARM に事前に用意された定義と一致しないためです。

上記のクエリを実行するには、次に示すように、結果セットのカラムの名前と型を明示的に指定します。

SELECT * FROM test_result_clause() WITH (x INTEGER, y INTEGER, z INTEGER);

WITH RESULT SET ON が指定されている場合は、実行時に、データベースサーバーは EXECUTE IMMEDIATE 文を処理し、結果セットを返します。ただし、WITH RESULT SET OFF が指定されているか、または句が省略されている場合でも、データベースサーバーは解析された文字列引数の最初の文の型については、同じように認識することができます。その文が SELECT 文であれば、結果セットを返します。それでは、前述した 2 番目の例を見てください。

CREATE OR REPLACE PROCEDURE test_result_clause()
BEGIN
    EXECUTE IMMEDIATE WITH RESULT SET OFF 'SELECT 1';
END;

Interactive SQL からこのプロシージャーを呼び出すとエラーにはなりません。ここで、1 つの SELECT 文ではなく、バッチが含まれたプロシージャーに変更するとします。

CREATE OR REPLACE PROCEDURE test_result_clause()
BEGIN
    EXECUTE IMMEDIATE WITH RESULT SET OFF 
    'begin declare v int; set v=1; select v; end';
END;

この場合には、test_result_clause プロシージャーを呼び出すと、エラー (SQLCODE -946, SQLSTATE 09W03) が発生します。

次の最後の例では、プロシージャー内で SELECT 文を EXECUTE IMMEDIATE 文の引数として構築して、プロシージャーが結果セットを返すようにする方法を示しています。



CREATE PROCEDURE DynamicResult(
   IN Columns LONG VARCHAR,
   IN TableName CHAR(128),
   IN Restriction LONG VARCHAR DEFAULT NULL )
BEGIN
    DECLARE Command LONG VARCHAR;
    SET Command = 'SELECT ' || Columns || ' FROM ' || TableName;
    IF ISNULL( Restriction,'') <> '' THEN
         SET Command = Command || ' WHERE ' || Restriction;
    END IF;
    EXECUTE IMMEDIATE WITH RESULT SET ON Command;
END;

このプロシージャーは次のように呼び出されます。

CALL DynamicResult(
   'table_id,table_name',
   'SYSTAB',
   'table_id <= 10');

これは次のような結果になります。

table_id table_name
1 ISYSTAB
2 ISYSTABCOL
3 ISYSIDX
... ...

上記の CALL では、プロシージャーで EXECUTE IMMEDIATE が使用されていても、正しく結果セットが返されます。ODBC などの一部のサーバー API では、PREPARE-DESCRIBE-EXECUTE-OR-OPEN を利用して要求が結合されており、結果セットを返すかどうかによって、文を実行するか、または開くかが選択されます。文が開かれる必要がある場合には、API またはアプリケーションは DESCRIBE CURSOR を続けて発行することによって、プロシージャーが作成されたときに構築された SYSPROCPARM システムビューの内容に依存するのではなく、実際の結果セットを把握できるようにします。この方法は、DBISQL でも DBISQLC でも使用されています。この場合、上記のプロシージャーの CALL はエラーにならずに実行されます。ただし、文の DESCRIBE の結果に依存するアプリケーションインターフェイスの場合は、どの文でも処理できるというわけではありません。

アトミックな複合文中では、COMMIT を行う EXECUTE IMMEDIATE 文は使えません。COMMIT 文はこのコンテキストでは許可されていません。

 参照