动态 SQL 是一项能够执行某些 SQL 命令的技术,这些命令直到即将执行时才是已知的。
到目前为止,在 SPL 程序中演示的 SQL 命令都是静态 SQL:必须先知道完整的命令(变量除外)并将其编码到程序中,然后程序本身才能开始执行。因此,通过使用动态 SQL,执行的 SQL 可在程序运行时发生更改。
此外,动态 SQL 是唯一可从 SPL 程序中执行数据定义命令(如CREATE TABLE)的唯一方式。
但是,请注意,动态 SQL 的运行时性能将比静态 SQL 慢。
EXECUTE IMMEDIATE 命令用于动态运行 SQL 命令。
EXECUTE IMMEDIATE 'sql_expression;'
[ INTO { variable [, ...] | record } ]
[ USING expression [, ...] ]
sql_expression 是一个字符串表达式,其中包含要动态执行的 SQL 命令。variable 通常从 SELECT 命令接收结果集的输出,该命令是因执行 sql_expression 中执行 SQL 命令而创建的。变量的数字、顺序必须与结果集字段的数字、顺序相匹配,并且变量的类型必须与结果集字段的类型兼容。换言之,只要记录字段的数字、顺序与结果集的相匹配,并且记录字段的类型与结果集的类型兼容,就可以指定记录。当使用 INTO 子句时,只能在结果集中刚好返回一行,否则会发生异常。当使用 USING 子句时,expression 的值将传递给占位符。占位符通过可使用变量的 sql_expression 嵌入在 SQL 命令中。占位符可由带有冒号前缀 (:) 的标识符 (:name) 表示。求值表达式的数字、顺序必须与 sql_expression 中占位符的数字、顺序相匹配,并且求值表达式的数据类型必须与这些占位符的类型兼容。请注意,占位符不在 SPL 程序的任何位置声明 – 它们仅出现在 sql_expression 中。
以下示例显示字符串文本形式的动态 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 命令的最后一次执行将结果返回到记录而不是各变量中。
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 语句的结果集装入一个已命名的集合中。