動態(tài) SQL 是一項能夠執(zhí)行某些 SQL 命令的技術(shù),這些命令直到即將執(zhí)行時才是已知的。
到目前為止,在 SPL 程序中演示的 SQL 命令都是靜態(tài) SQL:必須先知道完整的命令(變量除外)并將其編碼到程序中,然后程序本身才能開始執(zhí)行。因此,通過使用動態(tài) SQL,執(zhí)行的 SQL 可在程序運行時發(fā)生更改。
此外,動態(tài) SQL 是唯一可從 SPL 程序中執(zhí)行數(shù)據(jù)定義命令(如CREATE TABLE)的唯一方式。
但是,請注意,動態(tài) SQL 的運行時性能將比靜態(tài) SQL 慢。
EXECUTE IMMEDIATE 命令用于動態(tài)運行 SQL 命令。
EXECUTE IMMEDIATE 'sql_expression;'
[ INTO { variable [, ...] | record } ]
[ USING expression [, ...] ]
sql_expression 是一個字符串表達式,其中包含要動態(tài)執(zhí)行的 SQL 命令。variable 通常從 SELECT 命令接收結(jié)果集的輸出,該命令是因執(zhí)行 sql_expression 中執(zhí)行 SQL 命令而創(chuàng)建的。變量的數(shù)字、順序必須與結(jié)果集字段的數(shù)字、順序相匹配,并且變量的類型必須與結(jié)果集字段的類型兼容。換言之,只要記錄字段的數(shù)字、順序與結(jié)果集的相匹配,并且記錄字段的類型與結(jié)果集的類型兼容,就可以指定記錄。當(dāng)使用 INTO 子句時,只能在結(jié)果集中剛好返回一行,否則會發(fā)生異常。當(dāng)使用 USING 子句時,expression 的值將傳遞給占位符。占位符通過可使用變量的 sql_expression 嵌入在 SQL 命令中。占位符可由帶有冒號前綴 (:) 的標(biāo)識符 (:name) 表示。求值表達式的數(shù)字、順序必須與 sql_expression 中占位符的數(shù)字、順序相匹配,并且求值表達式的數(shù)據(jù)類型必須與這些占位符的類型兼容。請注意,占位符不在 SPL 程序的任何位置聲明 – 它們僅出現(xiàn)在 sql_expression 中。
以下示例顯示字符串文本形式的動態(tài) SQL 命令。
DECLARE
v_sql VARCHAR2(50);
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE job (jobno NUMBER(3),' ||
' jname VARCHAR2(9))';
v_sql := 'INSERT INTO job VALUES (100, ''ANALYST'')';
EXECUTE IMMEDIATE v_sql;
v_sql := 'INSERT INTO job VALUES (200, ''CLERK'')';
EXECUTE IMMEDIATE v_sql;
END;
以下示例闡釋用于將值傳遞給 SQL 字符串中的占位符的 USING 子句。
DECLARE
v_sql VARCHAR2(50) := 'INSERT INTO job VALUES ' ||
'(:p_jobno, :p_jname)';
v_jobno job.jobno%TYPE;
v_jname job.jname%TYPE;
BEGIN
v_jobno := 300;
v_jname := 'MANAGER';
EXECUTE IMMEDIATE v_sql USING v_jobno, v_jname;
v_jobno := 400;
v_jname := 'SALESMAN';
EXECUTE IMMEDIATE v_sql USING v_jobno, v_jname;
v_jobno := 500;
v_jname := 'PRESIDENT';
EXECUTE IMMEDIATE v_sql USING v_jobno, v_jname;
END;
以下示例顯示 INTO 和 USING 子句。請注意,SELECT 命令的最后一次執(zhí)行將結(jié)果返回到記錄而不是各變量中。
DECLARE
v_sql VARCHAR2(60);
v_jobno job.jobno%TYPE;
v_jname job.jname%TYPE;
r_job job%ROWTYPE;
BEGIN
DBMS_OUTPUT.PUT_LINE('JOBNO JNAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
v_sql := 'SELECT jobno, jname FROM job WHERE jobno = :p_jobno';
EXECUTE IMMEDIATE v_sql INTO v_jobno, v_jname USING 100;
DBMS_OUTPUT.PUT_LINE(v_jobno || ' ' || v_jname);
EXECUTE IMMEDIATE v_sql INTO v_jobno, v_jname USING 200;
DBMS_OUTPUT.PUT_LINE(v_jobno || ' ' || v_jname);
EXECUTE IMMEDIATE v_sql INTO v_jobno, v_jname USING 300;
DBMS_OUTPUT.PUT_LINE(v_jobno || ' ' || v_jname);
EXECUTE IMMEDIATE v_sql INTO v_jobno, v_jname USING 400;
DBMS_OUTPUT.PUT_LINE(v_jobno || ' ' || v_jname);
EXECUTE IMMEDIATE v_sql INTO r_job USING 500;
DBMS_OUTPUT.PUT_LINE(r_job.jobno || ' ' || r_job.jname);
END;
下面是上一匿名塊的輸出:
JOBNO JNAME
----- -------
100 ANALYST
200 CLERK
300 MANAGER
400 SALESMAN
500 PRESIDENT
您可以使用 BULK COLLECT 子句將 EXECUTE IMMEDIATE 語句的結(jié)果集裝入一個已命名的集合中。