I've been going over some PL/SQL (In Oracle SQL Developer), and have seen several different formats of SQL being called.
For the consistency and speed of current and future code, I'd like to know which is the preferred choice.
There are four types I've seen.
1) Plain DDL:
CREATE TABLE newtable AS SELECT * FROM pSource;
2) Execute Immediate (Native Dynamic 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);
Are there any particular advantages/disadvantages/restrictions between these different ways of calling?
1) You can't execute straight DDL inside of a PL/SQL block.
BEGIN
CREATE TABLE TEST AS (
SELECT * FROM FND_USER
);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
/
Yields:
PLS-00103: Encountered the symbol "CREATE" when expecting one of the following:
2) EXECUTE IMMEDIATE
(and its sister DBMS_SQL
) are used to execute SQL inside of a PL/SQL block. These differ from "regular" SQL in that they actually use a completely different SQL engine (in PL/SQL's case it runs in the oracle
process) to compute. This is why so many of us preach "if you can do it in SQL don't do it in PL/SQL".
Even these two options differ between how. EXECUTE IMMEDIATE
is quick and easy but kind of dumb. DBMS_SQL
is a little more complex but gives the developer a lot more control.
For instance this example that essentially describes the columns of a 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
Since DBMS_SQL
allows us to open and manipulate the cursor in which the PL/SQL block is operating inside of the result would be very difficult to reproduce in an EXECUTE IMMEDIATE
block (difficulty level: no selecting from ALL_TAB_COLS
this is just meant to be informative:).
3)EXEC_SQL
is a forms specific version of the above DBMS_SQL
. Use it wisely. :)
Here is a great breakdown of the above and here is Tom Kyte breaking it down like only he can.