Re: Dynamic SQL
Date: Wed, 24 Mar 1999 12:47:24 GMT
Message-ID: <36f8dcb1.1595964_at_192.86.155.100>
A copy of this was sent to Adam Gresh <adamzg_at_home.com> (if that email address didn't require changing) On Wed, 24 Mar 1999 03:44:25 GMT, you wrote:
>I looked over the documentation on ORACLE's site and found a small
>amount of information on dynamic SQL, but I couldn't make it work. Can
>anybody tell me how to run a simple string as SQL? The reason is that I
>would like to dynamically specify table and column names at run time.
>
>Something along the lines of...
You do not 'select .. into ...' in dynamic sql. You will
- parse a statement
- bind input variables/values (eg: select empno from emp where ename = :x, :x is a bind variable)
- you will bind OUTPUT variables to the query (in the above, empno is an output variable)
- you will execute the statement
- you will fetch rows and get the values of the bound column
Here is an example, it does 1, 3, 4, and 5 from above (no inputs to bind in this example):
create or replace function countem( p_tname in varchar2 ) return number is
l_theCursor integer default dbms_sql.open_cursor; l_columnValue number default NULL; l_status integer; begin dbms_sql.parse( l_theCursor, -- step 1 'select count(*) from ' || p_tname, dbms_sql.native );
dbms_sql.define_column( l_theCursor, 1, l_columnValue ); -- step 3
l_status := dbms_sql.execute(l_theCursor); -- step 4 if ( dbms_sql.fetch_rows(l_theCursor) > 0 ) then dbms_sql.column_value( l_theCursor, 1, l_columnValue ); -- step 5end if;
dbms_sql.close_cursor(l_theCursor);
return l_columnValue;
end countem;
/
SQL> exec dbms_output.put_line( countem( 'emp' ) ) 15
PL/SQL procedure successfully completed.
>declare
> clientvalue varchar(20);
> keyfielddata varchar(64);
> data varchar(64);
> selectclause varchar(300);
>begin
>data := 'Unassigned';
>clientvalue:='CLIENT';
>keyfielddata:='CLIENTID';
>selectclause := 'select ' || keyfielddata ||
> ' into data from ' || clientvalue;
>--select keyfielddata into data from "client";
>dbms_output.put_line (selectclause);
>--yields 'select CLIENTID into data from CLIENT'
>dbms_output.put_line (data);
>--yields 'Unassigned' since I can't get the query to execute.
>pause;
>EXEC selectclause;
>--EXECUTE selectclause;
>end;
>...but, of course, this does everything but execute the string as a
>query. I did notice that PL/SQL will resolve a variable if used as a
>column name, but not if used as a table name. That is, I can use the
no it won't. It will assume the column you are selecting is a bind variable. For example if you code:
declare
my_variable varchar2(25);
begin
for x in ( select my_variable from dual )
loop
...
end loop;
end;
it will *NOT* use the value of my_variable to find a column name, rather it will select the value of my_variable from the table (the above for example selects NULL from dual since my_variable is NULL. If I set my_variable := 'something' and then reexecute, it will select the constant 'something' from dual -- not a column named something).
>statement 'select keyfielddata into data from CLIENT' and get a result,
>but not 'select keyfielddata into data from clientvalue' (see sample
>below).
>
see above for an example of using bind variables with dbms_sql....
Also, you might want to:
SQL> select text from all_source where name = 'DBMS_SQL' and type = 'PACKAGE' order by line;
to see the 'readme' (has all the steps you need). As well, see the section in the application developers guide on dynamic sql -- it goes over dbms_sql as well.
Lastly, something to keep in mind:
roles are never enabled during the execution of a procedure.
Try this:
SQL> set role none;
SQL> "statement you want to test to see if it'll work in a procedure"
If you can do it in plus with no roles you can do it in a procedure. If you can't, you must have the privelege from a role and hence won't be able to do it in a procedure.
You probably have the privelege to do what you are trying to do in the procedure via a role. Grant the privelege directly to the owner of the procedure and it'll work.
So, if you create a procedure that uses dbms_sql and get "insufficient privs" or "identifier X does not exist", you probably have the priv to do what you are trying to do via a role... Do the above trick in sqlplus to confirm that and then get the priv granted to you...
>Sample output...
>SQL> set serveroutput on;
>SQL> declare
> 2 clientvalue varchar(20);
> 3 keyfielddata varchar(64);
> 4 data varchar(64);
> 5 selectclause varchar(300);
> 6 begin
> 7 --data := 'Unassigned';
> 8 clientvalue:='CLIENT';
> 9 keyfielddata:='CLIENTID';
> 10 select keyfielddata into data from CLIENT;
> 11 dbms_output.put_line (selectclause);
> 12 dbms_output.put_line (data);
> 13 --EXECUTE :selectclause;
> 14 end;
> 15 /
>CLIENTID
>
>PL/SQL procedure successfully completed.
>========================================================
>set serveroutput on;
>declare
> clientvalue varchar(20);
> keyfielddata varchar(64);
> data varchar(64);
> selectclause varchar(300);
>begin
>--data := 'Unassigned';
>clientvalue:='CLIENT';
>keyfielddata:='CLIENTID';
>select keyfielddata into data from clientvalue;
>dbms_output.put_line (selectclause);
>dbms_output.put_line (data);
>--EXECUTE :selectclause;
>end;
>
>ORA-06550: line 10, column 36:
>PLS-00356: 'CLIENTVALUE' must name a table to which the user has access
>ORA-06550: line 10, column 1:
>PL/SQL: SQL Statement ignored
>
>
>
>
>Anyone?
Thomas Kyte
tkyte_at_us.oracle.com
Oracle Service Industries
Reston, VA USA
-- http://govt.us.oracle.com/ -- downloadable utilities ---------------------------------------------------------------------------- Opinions are mine and do not necessarily reflect those of Oracle CorporationReceived on Wed Mar 24 1999 - 13:47:24 CET