動態(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é)果集裝入一個已命名的集合中。