Dynamic PL/SQL - oracle

In PL/SQL,I would like to pass a source as well as the target schema as a parameter to a stored procedure. For source we can use:
PROCEDURE select_from_schema( the_schema VARCHAR2)
IS
TYPE my_cursor_type IS REF CURSOR;
my_cursor my_cursor_type;
BEGIN
OPEN my_cursor FOR 'SELECT my_field FROM '||the_schema||'.my_table';
-- Do your FETCHes just as with a normal cursor
CLOSE my_cursor;
END;
For the target insert or update statement, how can we use that schema inside that insert or update statement....Does anyone know how could I do that???
P.S. Excuse me; I am a beginner and must get some functions written quickly.

You can do the same thing for an INSERT or UPDATE that you did for a SELECT - use dynamic SQL like this:
EXECUTE IMMEDIATE 'INSERT INTO '||target_schema||'.my_table (col1,col2...) VALUES(:val1, :val2...)' USING my_row.col1, my_row.col2...;

Related

Testing native dynamic SQL in Oracle before execution

I have implemented a certain feature in my application where the user can compose queries dynamically from the user interface by pushing around buttons and inserting some values here and there.
The user will not see the generated SQL statement at all.
I was wondering if there is a way to perhaps check the syntax and grammar (e.g. he opened a parantheses '(' and forgot to close it ) of the dynamically generated SQL to ensure that no run-time compilation errors would happen before actually executing the statement using EXECUTE IMMEDIATE.
You could use the dbms_sql.parse procedure to parse the SQL statement assuming the statement is DML not DDL. It would be rather unusual to parse a dynamic SQL statement using the dbms_sql package and then use EXECUTE IMMEDIATE to execute it rather than using dbms_sql.execute but nothing prevents you from mixing dbms_sql and execute immediate.
The code to just parse the SQL statement would be something like
DECLARE
l_cursor integer;
l_sql_stmt varchar2(1000) := <<some SQL statement>>;
BEGIN
l_cursor := dbms_sql.open_cursor;
dbms_sql.parse( l_cursor, l_sql_stmt, dbms_sql.native );
dbms_sql.close_cursor( l_cursor );
END;
You can also use explain plan, this is basically doing the first step of the execution.
SQL> explain plan for select * from dual;
Explained.
SQL is valid, you can also use the explain tables to get the tables, views etc, maybe even estimated run time ...
SQL> explain plan for select * from duall;
explain plan for select * from duall
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL is invalid, this is why ...
you can also use it in a dynamic statement
SQL> begin execute immediate 'explain plan for ' || ' select * from dual'; end;
2 /
PL/SQL procedure successfully completed.
As always use error-handling, e.g. write a little error log creater package or procedure what u call when it's needed.
DECLARE
my_stmt VARCHAR2(4000):='this will contain my statements';
BEGIN
'begin' || my_stmt || 'end';
EXCEPTION
WHEN OTHERS THEN
prc_my_error_log_creator();
END;
in the log_creator use for example the DBMS_UTILITY.FORMAT_ERROR_BACKTRACE() func to get the stack's contain.
Regards

Procedure created with compilation errors in oracle.?

I wrote simple stored procedure in oracle. but its shows procedure created with compilation errors.
My code is:
CREATE OR REPLACE PROCEDURE PRC_SELECT
AS
BEGIN
SELECT * FROM tb_name;
END;
/
Please help me to solve this problem.
This is a very basic skeleton, for your requirement.
CREATE OR REPLACE PROCEDURE PRC_SELECT(p_OLD IN VARCHAR2)
AS
my_rec tb_name%rowtype;
BEGIN
SELECT * into my_rec FROM tb_name WHERE old = p_OLD;
END;
/
my_rec will be created as a PL/SQL type whose structure would be table tb_name's structure!
a procedure cannot do a select * back to the screen.
you would have to bulk collect it into a collection and return it or open a cursor and return that.
a procedure is pl/sql, which doesn't directly write to the screen.
if you want it, you can use dbms_output.put_line to write each record.
you might also want to look into pipelined functions, which can be used in SQL later.
it depends what you're requirements are really.
If you really want to read all the rows in tb_name you could try:
CREATE OR REPLACE PROCEDURE PRC_SELECT
AS
BEGIN
FOR aRow IN (SELECT * FROM tb_name)
LOOP
DBMS_OUTPUT.PUT_LINE('Retrieved ' || aRow.SOME_FIELD);
END LOOP;
END;
Note that this may produce a lot of output if there are many rows in tb_name.
Share and enjoy.

How to get refcursor result/output to show as text?

I'm trying to call a stored procedure in Oracle and show the results of the call, the problem is that it crashes on the line FETCH v_cur into v_a; with error: ORA-06504: PL/SQL: Return types of Result Set variables or query do not match.
I guess the output of the query does not match v_a VARCHAR2(100), but I don't know what to put there instead. The stored procedure that's being called does a join of several tables and selects more than 20+ different columns belonging to different tables. So what I would want is to just view the output of the query without having to refer to each result column separately. How I would go and do this ?
I'm using SQL Navigator (not that important I guess).
DECLARE
v_cur SYS_REFCURSOR;
v_a VARCHAR2(100);
BEGIN
pkg_get_results.get_rows(v_cur,to_date('2012/04/12', 'yyyy/mm/dd'),to_date('2012/04/12', 'yyyy/mm/dd'), '','','','');
LOOP
FETCH v_cur into v_a; -- what to put here ?
EXIT WHEN v_cur%NOTFOUND;
dbms_output.put_line(v_a );
END LOOP;
CLOSE v_cur;
END;
SQL Navigator does have the ability to do this for you. How to do it exactly depends on your version of Navigator, and it's conceivable (though I don't know) some versions may not have it.
Instructions can be found in this thread: http://sqlnavigator.inside.quest.com/thread.jspa?threadID=2466
Incidentally, Toad also has this ability.

How to test an Oracle Stored Procedure with RefCursor return type?

I'm looking for a good explanation on how to test an Oracle stored procedure in SQL Developer or Embarcardero Rapid XE2. Thank you.
Something like
create or replace procedure my_proc( p_rc OUT SYS_REFCURSOR )
as
begin
open p_rc
for select 1 col1
from dual;
end;
/
variable rc refcursor;
exec my_proc( :rc );
print rc;
will work in SQL*Plus or SQL Developer. I don't have any experience with Embarcardero Rapid XE2 so I have no idea whether it supports SQL*Plus commands like this.
Something like this lets you test your procedure on almost any client:
DECLARE
v_cur SYS_REFCURSOR;
v_a VARCHAR2(10);
v_b VARCHAR2(10);
BEGIN
your_proc(v_cur);
LOOP
FETCH v_cur INTO v_a, v_b;
EXIT WHEN v_cur%NOTFOUND;
dbms_output.put_line(v_a || ' ' || v_b);
END LOOP;
CLOSE v_cur;
END;
Basically, your test harness needs to support the definition of a SYS_REFCURSOR variable and the ability to call your procedure while passing in the variable you defined, then loop through the cursor result set. PL/SQL does all that, and anonymous blocks are easy to set up and maintain, fairly adaptable, and quite readable to anyone who works with PL/SQL.
Another, albeit similar way would be to build a named procedure that does the same thing, and assuming the client has a debugger (like SQL Developer, PL/SQL Developer, TOAD, etc.) you could then step through the execution.
In SQL Developer you can right-click on the package body then select RUN. The 'Run PL/SQL' window will let you edit the PL/SQL Block. Clicking OK will give you a window pane titled 'Output Variables - Log' with an output variables tab. You can select your output variables on the left and the result is shown on the right side. Very handy and fast.
I've used Rapid with T-SQL and I think there was something similiar to this.
Writing your own delcare-begin-end script where you loop through the cursor, as with DCookie's example, is always a good exercise to do every now and then. It will work with anything and you will know that your code works.
In Toad 10.1.1.8 I use:
variable salida refcursor
exec MY_PKG.MY_PRC(1, 2, 3, :salida) -- 1, 2, 3 are params
print salida
Then, Execute as Script.
I think this link will be enough for you. I found it when I was searching for the way to execute oracle procedures.
The link to the page
Short Description:
--cursor variable declaration
variable Out_Ref_Cursor refcursor;
--execute procedure
execute get_employees_name(IN_Variable,:Out_Ref_Cursor);
--display result referenced by ref cursor.
print Out_Ref_Cursor;
create or replace procedure my_proc( v_number IN number,p_rc OUT SYS_REFCURSOR )
as
begin
open p_rc
for select 1 col1
from dual;
end;
/
and then write a function lie this which calls your stored procedure
create or replace function my_proc_test(v_number IN NUMBER) RETURN sys_refcursor
as
p_rc sys_refcursor;
begin
my_proc(v_number,p_rc);
return p_rc;
end
/
then you can run this SQL query in the SQLDeveloper editor.
SELECT my_proc_test(3) FROM DUAL;
you will see the result in the console right click on it and cilck on single record view and edit the result you can see the all the records that were returned by the ref cursor.

In PL/SQL, can I pass the table schema of a cursor FROM clause via a stored procedure parameter?

In PL/SQL, I would like to pass in a "source" schema as a parameter to a stored procedure. For instance:
BEGIN
CURSOR my_cursor IS
SELECT my_field FROM <schema>.my_table
...
I want the 'schema' value to come from an input parameter into the stored procedure. Does anyone know how I could do that?
P.S. Sorry if this is a stupid simple question, but I'm new to PL/SQL and must get some functions written quickly.
In addition to what Mark Brady said, another dynamic SQL option is to use a REF CURSOR. Since your sample code includes a cursor this would be the most relevant.
PROCEDURE select_from_schema( the_schema VARCHAR2)
IS
TYPE my_cursor_type IS REF CURSOR;
my_cursor my_cursor_type;
BEGIN
OPEN my_cursor FOR 'SELECT my_field FROM '||the_schema||'.my_table';
-- Do your FETCHes just as with a normal cursor
CLOSE my_cursor;
END;
This has to be done with dynamic sql.
Either the DBMS_SQL package or the Execute Immediate statement.
You can't use variables in the FROM clause.
A potential solution may be to
ALTER SESSION SET Current_Schema = '' <-- the schema you want.
That command changes the default schema. SO if you have a bunch of identically named tables you can save yourself dynamic SQL and make a Dynamic Alter Session.

Resources