システム固有の動的SQL
システム固有の動的SQLでは、EXECUTE
IMMEDIATE
文を使用してほとんどの動的SQL文を処理します。
動的SQL文が複数行を戻すSELECT
文である場合、システム固有の動的SQLでは、次のいずれかを選択できます。
-
BULK
COLLECT
INTO
句を指定してEXECUTE
IMMEDIATE
文を使用します。 -
OPEN
FOR
文、FETCH
文およびCLOSE
文を使用します。
SQLのカーソル属性は、システム固有の動的SQLのINSERT
文、UPDATE
文、DELETE
文、MERGE
文および単一行のSELECT
文の後では、それらの文が静的SQL文に対して動作する場合と同様に動作します。SQLのカーソル属性の詳細は、「カーソルの概要」を参照してください。
ここでのトピック
EXECUTE IMMEDIATE文
EXECUTE
IMMEDIATE
文は、システム固有の動的SQLがほとんどの動的SQL文を処理する際に使用する手段です。
動的SQL文が自己完結型である場合(つまり、バインド変数のプレースホルダがなく、戻すことができる結果がエラーのみである場合)、EXECUTE
IMMEDIATE
文に句は不要です。
動的SQL文にバインド変数のプレースホルダが含まれている場合、各プレースホルダは、次のように、EXECUTE
IMMEDIATE
文の適切な句内に対応するバインド変数を持っている必要があります。
-
動的SQL文が最大で1行を戻すことができる
SELECT
文である場合、アウトバインド変数(定義)をINTO
句に、インバインド変数をUSING
句に含めます。 -
動的SQL文が複数行を戻すことができる
SELECT
文である場合、アウトバインド変数(定義)をBULK
COLLECT
INTO
句に、インバインド変数をUSING
句に含めます。 -
動的SQL文が、
RETURNING
INTO
句が指定されていないDML文(SELECT
以外)である場合、すべてのバインド変数をUSING
句に含めます。 -
動的SQL文が
RETURNING
INTO
句が指定されているDML文である場合、インバインド変数をUSING
句に、アウトバインド変数をRETURNING
INTO
句に含めます。 -
動的SQL文が無名PL/SQLブロックまたは
CALL
文である場合、すべてのバインド変数をUSING
句に含めます。動的SQL文がサブプログラムを起動する場合は、次のことを確認します。
-
サブプログラムが、スキーマ・レベルで作成されているか、またはパッケージ仕様部で宣言および定義されていること。
-
サブプログラム・パラメータのプレースホルダに対応しているすべてのバインド変数のパラメータ・モードがそのサブプログラム・パラメータと同じであること、およびこのバインド変数のデータ型がそのサブプログラム・パラメータのデータ型と互換性があること。
-
いずれのバインド変数も予約語
NULL
ではないこと。この制限を回避するには、例8-7に示すように、
NULL
を使用する場所に未初期化変数を使用します。 -
いずれのバインド変数も、SQLでサポートされないデータ型(文字列により索引付けされる連想配列など)を持たないこと。
データ型がコレクションまたはレコード型である場合は、パッケージ仕様部で宣言されている必要があります。
-
ノート:
バインド変数はどのような順序でも評価できます。プログラムにより評価の順序が決定される場合は、プログラムで決定が行われる時点で動作は定義されません。
例8-4、例8-5および例8-6では、動的PL/SQLブロックは、PL/SQLコレクション型の仮パラメータを持つサブプログラムを起動する無名PL/SQLブロックです。コレクション型はSQLデータ型ではありません。各例では、コレクション型はパッケージ仕様部で宣言され、サブプログラムはパッケージ仕様部で宣言され、パッケージ本体で定義されます。
関連項目:
-
スキーマ・レベルでのファンクション作成の詳細は、「CREATE FUNCTION文」を参照してください
-
スキーマ・レベルでのプロシージャ作成の詳細は、「CREATE PROCEDURE文」を参照してください
-
パッケージの詳細は、「PL/SQLパッケージ」を参照してください
-
パッケージ内のサブプログラムの宣言の詳細は、「CREATE PACKAGE文」を参照してください
-
パッケージ内のサブプログラムの宣言および定義の詳細は、「CREATE PACKAGE BODY文」を参照してください
-
パッケージ仕様での型の宣言の詳細は、「CREATE PACKAGE文」を参照してください
-
EXECUTE
IMMEDIATE
文の構文の詳細は、「EXECUTE IMMEDIATE文」を参照してください -
コレクション型の詳細は、「PL/SQLのコレクションおよびレコード」を参照してください
例8-1 動的PL/SQLブロックからのサブプログラムの起動
この例では、動的PL/SQLブロックは、スキーマ・レベルで作成されたサブプログラムを起動する無名PL/SQLブロックです。
-- Subprogram that dynamic PL/SQL block invokes:
CREATE OR REPLACE PROCEDURE create_dept (
deptid IN OUT NUMBER,
dname IN VARCHAR2,
mgrid IN NUMBER,
locid IN NUMBER
) AUTHID DEFINER AS
BEGIN
deptid := departments_seq.NEXTVAL;
INSERT INTO departments (
department_id,
department_name,
manager_id,
location_id
)
VALUES (deptid, dname, mgrid, locid);
END;
/
DECLARE
plsql_block VARCHAR2(500);
new_deptid NUMBER(4);
new_dname VARCHAR2(30) := 'Advertising';
new_mgrid NUMBER(6) := 200;
new_locid NUMBER(4) := 1700;
BEGIN
-- Dynamic PL/SQL block invokes subprogram:
plsql_block := 'BEGIN create_dept(:a, :b, :c, :d); END;';
/* Specify bind variables in USING clause.
Specify mode for first parameter.
Modes of other parameters are correct by default. */
EXECUTE IMMEDIATE plsql_block
USING IN OUT new_deptid, new_dname, new_mgrid, new_locid;
END;
/
例8-2 BOOLEAN仮パラメータを持つサブプログラムの動的起動
この例では、動的PL/SQLブロックは、PL/SQLデータ型BOOLEAN
の仮パラメータを持つサブプログラムを起動する無名PL/SQLブロックです。
CREATE OR REPLACE PROCEDURE p (x BOOLEAN) AUTHID DEFINER AS
BEGIN
IF x THEN
DBMS_OUTPUT.PUT_LINE('x is true');
END IF;
END;
/
DECLARE
dyn_stmt VARCHAR2(200);
b BOOLEAN := TRUE;
BEGIN
dyn_stmt := 'BEGIN p(:x); END;';
EXECUTE IMMEDIATE dyn_stmt USING b;
END;
/
結果:
x is true
例8-3 RECORD仮パラメータを持つサブプログラムの動的起動
この例では、動的PL/SQLブロックは、PL/SQL(SQLではなく)データ型RECORD
の仮パラメータを持つサブプログラムを起動する無名PL/SQLブロックです。レコード型はパッケージ仕様部で宣言され、サブプログラムはパッケージ仕様部で宣言され、パッケージ本体で定義されます。
CREATE OR REPLACE PACKAGE pkg AUTHID DEFINER AS
TYPE rec IS RECORD (n1 NUMBER, n2 NUMBER);
PROCEDURE p (x OUT rec, y NUMBER, z NUMBER);
END pkg;
/
CREATE OR REPLACE PACKAGE BODY pkg AS
PROCEDURE p (x OUT rec, y NUMBER, z NUMBER) AS
BEGIN
x.n1 := y;
x.n2 := z;
END p;
END pkg;
/
DECLARE
r pkg.rec;
dyn_str VARCHAR2(3000);
BEGIN
dyn_str := 'BEGIN pkg.p(:x, 6, 8); END;';
EXECUTE IMMEDIATE dyn_str USING OUT r;
DBMS_OUTPUT.PUT_LINE('r.n1 = ' || r.n1);
DBMS_OUTPUT.PUT_LINE('r.n2 = ' || r.n2);
END;
/
結果:
r.n1 = 6
r.n2 = 8
例8-4 連想を持つサブプログラムの動的起動配列仮パラメータ
この例では、動的PL/SQLブロックは、PLS_INTEGER
で索引付けされる連想配列のPL/SQLコレクション型の仮パラメータを持つサブプログラムを起動する無名PL/SQLブロックです。
ノート:
このコンテキストで使用される連想配列は、PLS_INTEGER
を使用して索引付けする必要があります。
CREATE OR REPLACE PACKAGE pkg AUTHID DEFINER AS
TYPE number_names IS TABLE OF VARCHAR2(5)
INDEX BY PLS_INTEGER;
PROCEDURE print_number_names (x number_names);
END pkg;
/
CREATE OR REPLACE PACKAGE BODY pkg AS
PROCEDURE print_number_names (x number_names) IS
BEGIN
FOR i IN x.FIRST .. x.LAST LOOP
DBMS_OUTPUT.PUT_LINE(x(i));
END LOOP;
END;
END pkg;
/
DECLARE
digit_names pkg.number_names;
dyn_stmt VARCHAR2(3000);
BEGIN
digit_names(0) := 'zero';
digit_names(1) := 'one';
digit_names(2) := 'two';
digit_names(3) := 'three';
digit_names(4) := 'four';
digit_names(5) := 'five';
digit_names(6) := 'six';
digit_names(7) := 'seven';
digit_names(8) := 'eight';
digit_names(9) := 'nine';
dyn_stmt := 'BEGIN pkg.print_number_names(:x); END;';
EXECUTE IMMEDIATE dyn_stmt USING digit_names;
END;
/
結果:
zero
one
two
...
nine
例8-5 ネストした表仮パラメータを持つサブプログラムの動的起動
この例では、動的PL/SQLブロックは、ネストした表のPL/SQLコレクション型の仮パラメータを持つサブプログラムを起動する無名PL/SQLブロックです。
CREATE OR REPLACE PACKAGE pkg AUTHID DEFINER AS
TYPE names IS TABLE OF VARCHAR2(10);
PROCEDURE print_names (x names);
END pkg;
/
CREATE OR REPLACE PACKAGE BODY pkg AS
PROCEDURE print_names (x names) IS
BEGIN
FOR i IN x.FIRST .. x.LAST LOOP
DBMS_OUTPUT.PUT_LINE(x(i));
END LOOP;
END;
END pkg;
/
DECLARE
fruits pkg.names;
dyn_stmt VARCHAR2(3000);
BEGIN
fruits := pkg.names('apple', 'banana', 'cherry');
dyn_stmt := 'BEGIN pkg.print_names(:x); END;';
EXECUTE IMMEDIATE dyn_stmt USING fruits;
END;
/
結果:
apple
banana
cherry
例8-6 VARRAY仮パラメータを持つサブプログラムの動的起動
この例では、動的PL/SQLブロックは、PL/SQLコレクション型VARRAYの仮パラメータを持つサブプログラムを起動する無名PL/SQLブロックです。
CREATE OR REPLACE PACKAGE pkg AUTHID DEFINER AS
TYPE foursome IS VARRAY(4) OF VARCHAR2(5);
PROCEDURE print_foursome (x foursome);
END pkg;
/
CREATE OR REPLACE PACKAGE BODY pkg AS
PROCEDURE print_foursome (x foursome) IS
BEGIN
IF x.COUNT = 0 THEN
DBMS_OUTPUT.PUT_LINE('Empty');
ELSE
FOR i IN x.FIRST .. x.LAST LOOP
DBMS_OUTPUT.PUT_LINE(x(i));
END LOOP;
END IF;
END;
END pkg;
/
DECLARE
directions pkg.foursome;
dyn_stmt VARCHAR2(3000);
BEGIN
directions := pkg.foursome('north', 'south', 'east', 'west');
dyn_stmt := 'BEGIN pkg.print_foursome(:x); END;';
EXECUTE IMMEDIATE dyn_stmt USING directions;
END;
/
結果:
north
south
east
west
例8-7 USING句でのNULLを表現する未初期化変数
この例では、未初期化変数を使用して、USING
句内で予約語NULL
を表現しています。
CREATE TABLE employees_temp AS SELECT * FROM EMPLOYEES;
DECLARE
a_null CHAR(1); -- Set to NULL automatically at run time
BEGIN
EXECUTE IMMEDIATE 'UPDATE employees_temp SET commission_pct = :x'
USING a_null;
END;
/
OPEN FOR文、FETCH文およびCLOSE文
動的SQL文が複数行を戻すSELECT
文である場合は、システム固有の動的SQLを使用してその文を次のように処理できます。
-
OPEN
FOR
文を使用して、カーソル変数を動的SQL文に関連付けます。OPEN
FOR
文のUSING
句で、動的SQL文内の各プレースホルダにバインド変数を指定します。USING
句に、リテラルNULL
を含めることはできません。この制限を回避するには、例8-7に示すように、NULL
を使用する場所に未初期化変数を使用します。 -
FETCH
文を使用して、結果セットの行を一度に1行、複数行またはすべて取り出します。 -
CLOSE
文を使用して、カーソル変数をクローズします。
コレクションが「コレクションの問合せ」に示す条件を満たしていれば、動的SQL文でコレクションを問い合せることができます。
関連項目:
-
構文の詳細は、「OPEN FOR文」を参照してください
-
構文の詳細は、「FETCH文」を参照してください
-
構文の詳細は、「CLOSE文」を参照してください
例8-8 OPEN FOR文、FETCH文およびCLOSE文を使用したシステム固有の動的SQL
この例では、結果セットの行を一度に1行ずつ取り出して、マネージャであるすべての従業員を表示しています。
DECLARE
TYPE EmpCurTyp IS REF CURSOR;
v_emp_cursor EmpCurTyp;
emp_record employees%ROWTYPE;
v_stmt_str VARCHAR2(200);
v_e_job employees.job_id%TYPE;
BEGIN
-- Dynamic SQL statement with placeholder:
v_stmt_str := 'SELECT * FROM employees WHERE job_id = :j';
-- Open cursor & specify bind variable in USING clause:
OPEN v_emp_cursor FOR v_stmt_str USING 'MANAGER';
-- Fetch rows from result set one at a time:
LOOP
FETCH v_emp_cursor INTO emp_record;
EXIT WHEN v_emp_cursor%NOTFOUND;
END LOOP;
-- Close cursor:
CLOSE v_emp_cursor;
END;
/
例8-9 システム固有の動的SQLを使用したコレクションの問合せ
この例は例7-30と似ていますが、コレクション変数v1
がバインド変数である点が異なります。
CREATE OR REPLACE PACKAGE pkg AUTHID DEFINER AS TYPE rec IS RECORD(f1 NUMBER, f2 VARCHAR2(30)); TYPE mytab IS TABLE OF rec INDEX BY pls_integer; END; / DECLARE v1 pkg.mytab; -- collection of records v2 pkg.rec; c1 SYS_REFCURSOR; BEGIN OPEN c1 FOR 'SELECT * FROM TABLE(:1)' USING v1; FETCH c1 INTO v2; CLOSE c1; DBMS_OUTPUT.PUT_LINE('Values in record are ' || v2.f1 || ' and ' || v2.f2); END; /
動的SQL文内でのプレースホルダ名の繰返し
動的SQL文内でプレースホルダ名を繰り返す場合は、プレースホルダをバインド変数に関連付ける方法が動的SQL文の種類によって異なるということに注意してください。
ここでのトピック
動的SQL文が無名ブロックまたはCALL文でない
動的SQL文が無名PL/SQLブロックまたはCALL
文を表していない場合、プレースホルダ名の繰返しは重要ではありません。
プレースホルダは、名前ではなく位置によって、USING
句内のバインド変数に関連付けられます。
たとえば、次の動的SQL文では、:x
という名前の繰返しは重要ではありません。
sql_stmt := 'INSERT INTO payroll VALUES (:x, :x, :y, :x)';
対応するUSING
句では、4つのバインド変数を指定する必要があります。それらは異なっていてもかまいません。たとえば:
EXECUTE IMMEDIATE sql_stmt USING a, b, c, d;
前述のEXECUTE
IMMEDIATE
文は、次のSQL文を実行します。
INSERT INTO payroll VALUES (a, b, c, d)
:x
が出現するたびに、それぞれに同じバインド変数を関連付けるには、そのバインド変数を繰り返す必要があります。たとえば:
EXECUTE IMMEDIATE sql_stmt USING a, a, b, a;
前述のEXECUTE
IMMEDIATE
文は、次のSQL文を実行します。
INSERT INTO payroll VALUES (a, a, b, a)
動的SQL文が無名ブロックまたはCALL文
動的SQL文が無名PL/SQLブロックまたはCALL
文を表している場合、プレースホルダ名の繰返しは重要です。
一意のプレースホルダ名が、それぞれUSING
句内に対応するバインド変数を持っている必要があります。プレースホルダ名を繰り返す場合、それに対応するバインド変数を繰り返す必要はありません。そのプレースホルダ名に対するすべての参照がUSING
句内の1つのバインド変数に対応します。
例8-10 動的PL/SQLブロックで繰り返されるプレースホルダ名
この例では、最初の一意のプレースホルダ名:x
に対するすべての参照がUSING
句内の最初のバインド変数a
に関連付けられており、2番目の一意のプレースホルダ名:y
がUSING
句内の2番目のバインド変数b
に関連付けられています。
CREATE PROCEDURE calc_stats (
w NUMBER,
x NUMBER,
y NUMBER,
z NUMBER )
IS
BEGIN
DBMS_OUTPUT.PUT_LINE(w + x + y + z);
END;
/
DECLARE
a NUMBER := 4;
b NUMBER := 7;
plsql_block VARCHAR2(100);
BEGIN
plsql_block := 'BEGIN calc_stats(:x, :x, :y, :x); END;';
EXECUTE IMMEDIATE plsql_block USING a, b; -- calc_stats(a, a, b, a)
END;
/
結果:
19