Difference between EXEC_SQL, EXECUTE IMMEDIATE, DBMS_SQL and inline SQL
Asked Answered
S

1

6

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?

Spratt answered 1/5, 2015 at 5:52 Comment(0)
R
9

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.

Reinareinald answered 1/5, 2015 at 12:43 Comment(1)
Thanks for that. I was mistaken about seeing straight SQL, I think. The inline I saw was like this: CURSOR cur IS SELECT table_name FROM cols and this SELECT table_name FROM cols INTO types. I assumed that this meant that any SQL could be done like this.Spratt

© 2022 - 2024 — McMap. All rights reserved.