EXEC_SQL、EXECUTE IMMEDIATE、DBMS_SQL 和内联 SQL 之间的区别
Difference between EXEC_SQL, EXECUTE IMMEDIATE, DBMS_SQL and inline SQL
我研究了一些 PL/SQL(在 Oracle SQL Developer 中),并且看到了几种不同格式的 SQL 被调用。
为了当前和未来代码的一致性和速度,我想知道哪个是首选。
我见过四种。
1) 普通 DDL:
CREATE TABLE newtable AS SELECT * FROM pSource;
2) 立即执行(本机动态 SQL):
statement := 'CREATE TABLE newtable AS SELECT * FROM ' || pSource;
EXECUTE IMMEDIATE statement;
3) EXEC_SQL:
EXEC_SQL('CREATE TABLE newtable AS SELECT * FROM ' || pSource);
4) DBMS_SQL:
cursor := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(cursor, 'CREATE TABLE newtable AS SELECT * FROM ' || pSource, DBMS_SQL.NATIVE);
numRows := DBMS_SQL.EXECUTE(cursor);
这些不同的调用方式有什么特别的advantages/disadvantages/restrictions吗?
1) 您不能在 PL/SQL 块内直接执行 DDL。
BEGIN
CREATE TABLE TEST AS (
SELECT * FROM FND_USER
);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
/
产量:
PLS-00103: Encountered the symbol "CREATE" when expecting one of the following:
2) EXECUTE IMMEDIATE
(及其姐妹DBMS_SQL
)用于在PL/SQL 块内执行SQL。它们与 "regular" SQL 的不同之处在于它们实际上使用完全不同的 SQL 引擎(在 PL/SQL 的情况下它在 oracle
进程中运行)来计算.这就是为什么我们这么多人鼓吹 "if you can do it in SQL don't do it in PL/SQL".
即使这两个选项之间也有不同。 EXECUTE IMMEDIATE
既快速又简单,但有点笨。 DBMS_SQL
稍微复杂一些,但为开发人员提供了更多控制权。
例如,这个示例基本上描述了 table:
的列
declare
c number;
d number;
col_cnt integer;
f boolean;
rec_tab dbms_sql.desc_tab;
col_num number;
procedure print_rec(rec in dbms_sql.desc_rec) is
begin
dbms_output.new_line;
dbms_output.put_line('col_type = '
|| rec.col_type);
dbms_output.put_line('col_maxlen = '
|| rec.col_max_len);
dbms_output.put_line('col_name = '
|| rec.col_name);
dbms_output.put_line('col_name_len = '
|| rec.col_name_len);
dbms_output.put_line('col_schema_name = '
|| rec.col_schema_name);
dbms_output.put_line('col_schema_name_len = '
|| rec.col_schema_name_len);
dbms_output.put_line('col_precision = '
|| rec.col_precision);
dbms_output.put_line('col_scale = '
|| rec.col_scale);
dbms_output.put('col_null_ok = ');
if (rec.col_null_ok) then
dbms_output.put_line('true');
else
dbms_output.put_line('false');
end if;
end;
begin
c := dbms_sql.open_cursor;
dbms_sql.parse(c, 'select * from fnd_user', dbms_sql.native);
d := dbms_sql.execute(c);
dbms_sql.describe_columns(c, col_cnt, rec_tab);
/*
* Following loop could simply be for j in 1..col_cnt loop.
* Here we are simply illustrating some of the PL/SQL table
* features.
*/
col_num := rec_tab.first;
if (col_num is not null) then
loop
print_rec(rec_tab(col_num));
col_num := rec_tab.next(col_num);
exit when (col_num is null);
end loop;
end if;
dbms_sql.close_cursor(c);
end;
/
Source
由于 DBMS_SQL
允许我们打开和操作 PL/SQL 块在其中运行的游标,结果将很难在 EXECUTE IMMEDIATE
块中重现(难度级别:不选择ALL_TAB_COLS
这只是为了提供信息:)。
3)EXEC_SQL
是上述 DBMS_SQL
的特定形式版本。明智地使用它。 :)
Here is a great breakdown of the above and here 汤姆·凯特 (Tom Kyte) 像他一样打破它。
我研究了一些 PL/SQL(在 Oracle SQL Developer 中),并且看到了几种不同格式的 SQL 被调用。
为了当前和未来代码的一致性和速度,我想知道哪个是首选。
我见过四种。
1) 普通 DDL:
CREATE TABLE newtable AS SELECT * FROM pSource;
2) 立即执行(本机动态 SQL):
statement := 'CREATE TABLE newtable AS SELECT * FROM ' || pSource;
EXECUTE IMMEDIATE statement;
3) EXEC_SQL:
EXEC_SQL('CREATE TABLE newtable AS SELECT * FROM ' || pSource);
4) DBMS_SQL:
cursor := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(cursor, 'CREATE TABLE newtable AS SELECT * FROM ' || pSource, DBMS_SQL.NATIVE);
numRows := DBMS_SQL.EXECUTE(cursor);
这些不同的调用方式有什么特别的advantages/disadvantages/restrictions吗?
1) 您不能在 PL/SQL 块内直接执行 DDL。
BEGIN
CREATE TABLE TEST AS (
SELECT * FROM FND_USER
);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
/
产量:
PLS-00103: Encountered the symbol "CREATE" when expecting one of the following:
2) EXECUTE IMMEDIATE
(及其姐妹DBMS_SQL
)用于在PL/SQL 块内执行SQL。它们与 "regular" SQL 的不同之处在于它们实际上使用完全不同的 SQL 引擎(在 PL/SQL 的情况下它在 oracle
进程中运行)来计算.这就是为什么我们这么多人鼓吹 "if you can do it in SQL don't do it in PL/SQL".
即使这两个选项之间也有不同。 EXECUTE IMMEDIATE
既快速又简单,但有点笨。 DBMS_SQL
稍微复杂一些,但为开发人员提供了更多控制权。
例如,这个示例基本上描述了 table:
declare
c number;
d number;
col_cnt integer;
f boolean;
rec_tab dbms_sql.desc_tab;
col_num number;
procedure print_rec(rec in dbms_sql.desc_rec) is
begin
dbms_output.new_line;
dbms_output.put_line('col_type = '
|| rec.col_type);
dbms_output.put_line('col_maxlen = '
|| rec.col_max_len);
dbms_output.put_line('col_name = '
|| rec.col_name);
dbms_output.put_line('col_name_len = '
|| rec.col_name_len);
dbms_output.put_line('col_schema_name = '
|| rec.col_schema_name);
dbms_output.put_line('col_schema_name_len = '
|| rec.col_schema_name_len);
dbms_output.put_line('col_precision = '
|| rec.col_precision);
dbms_output.put_line('col_scale = '
|| rec.col_scale);
dbms_output.put('col_null_ok = ');
if (rec.col_null_ok) then
dbms_output.put_line('true');
else
dbms_output.put_line('false');
end if;
end;
begin
c := dbms_sql.open_cursor;
dbms_sql.parse(c, 'select * from fnd_user', dbms_sql.native);
d := dbms_sql.execute(c);
dbms_sql.describe_columns(c, col_cnt, rec_tab);
/*
* Following loop could simply be for j in 1..col_cnt loop.
* Here we are simply illustrating some of the PL/SQL table
* features.
*/
col_num := rec_tab.first;
if (col_num is not null) then
loop
print_rec(rec_tab(col_num));
col_num := rec_tab.next(col_num);
exit when (col_num is null);
end loop;
end if;
dbms_sql.close_cursor(c);
end;
/
Source
由于 DBMS_SQL
允许我们打开和操作 PL/SQL 块在其中运行的游标,结果将很难在 EXECUTE IMMEDIATE
块中重现(难度级别:不选择ALL_TAB_COLS
这只是为了提供信息:)。
3)EXEC_SQL
是上述 DBMS_SQL
的特定形式版本。明智地使用它。 :)
Here is a great breakdown of the above and here 汤姆·凯特 (Tom Kyte) 像他一样打破它。