I'm having trouble with dynamic sql, Issue is (I think) reading and setting global variable. Here's what I have and any help at all is greatly appreciated. Please let me know if you need table data too although I have included the data in comments.
CREATE OR REPLACE PACKAGE data_load
IS
curr_rec NUMBER;
curr_rule VARCHAR2(200);
curr_sql VARCHAR2(4000);
curr_sql_two VARCHAR2(4000);
curr_data_element VARCHAR2 (200);
curr_rule_text VARCHAR2(200);
curr_error_code VARCHAR2(10);
curr_error_flag VARCHAR2(10);
curr_flag_val NUMBER;
v_check NUMBER;
v_ID NUMBER;
cur_hdl INT ;
rows_processed NUMBER;
PROCEDURE check_rules;
END data_load;
The package body:
create or replace PACKAGE BODY data_load IS
PROCEDURE check_rules IS
CURSOR c1
IS
SELECT * FROM STAGING_TABLE where rownum < 3;
CURSOR c2
IS
SELECT * FROM ERROR_CODES WHERE rule_text IS NOT NULL AND status =1;
BEGIN
FOR rec1 IN c1
LOOP
FOR rec2 IN c2
LOOP
curr_data_element := 'rec1.'||rec2.data_element; --- this results in value "rec1.SHIP_FROM_ACCOUNT_ORG_CODE" without quotes
curr_rule_text := rec2.rule_text; --- this value is "is not null" without quotes
curr_error_flag := rec2.error_flag; --this value is "FLAG_03" without quotes
curr_flag_val := to_number(rec2.error_code); --- this value is 31
curr_sql :='begin if :curr_data_element '||curr_rule_text||' then update table_with_column_FLAG_03 set '||curr_error_flag ||' = 0; else update table_with_column_FLAG_03 set '||curr_error_flag ||' = '||curr_flag_val||'; end if; end;';
dbms_output.put_line(curr_sql); -- results in "begin if :curr_data_element is null then update table_with_column_FLAG_03 set FLAG_03 = 0; else update table_with_column_FLAG_03 set FLAG_03 = 31; end if; end;"
EXECUTE IMMEDIATE curr_sql USING curr_data_element ; -- this always updates the column with 31 even when curr_data_element/ rec1.SHIP_FROM_ACCOUNT_ORG_CODE is null and that's the problem
COMMIT;
END LOOP;
curr_rec := curr_rec+1;
END LOOP;
dbms_output.put_line(curr_rec);
END check_rules;
END data_load;
You've already highlighted the problem really:
curr_data_element := 'rec1.'||rec2.data_element; --- this results in value "rec1.SHIP_FROM_ACCOUNT_ORG_CODE" without quotes
You can't refer to cursor columns dynamically. You are creating a string with value 'rec1.SHIP_FROM_ACCOUNT_ORG_CODE'; there is no mechanism to evaluate what that represents. You can't, for instance, try to dynamically select that from dual because the rec1 is not in scope for a SQL call, even dynamically.
When you bind that string value it is never going to be null. You are using that string, not the value in the outer cursor that it represents, and essentially you cannot do that.
The simplest way to deal with this, if you have a reasonably small number of columns in your staging table that might appear as the rec2.data_element value, is to use a case expression to assign the appropriate actual rec1 column value to the curr_data_element variable, based on the rec2.data_element value:
...
BEGIN
FOR rec1 IN c1
LOOP
FOR rec2 IN c2
LOOP
curr_data_element :=
case rec2.data_element
when 'SHIP_FROM_ACCOUNT_ORG_CODE' then rec1.SHIP_FROM_ACCOUNT_ORG_CODE
when 'ANOTHER_COLUMN' then rec1.ANOTHER_COLUMN
-- when ... -- repeat for all possible columns
end;
curr_rule_text := rec2.rule_text;
...
If you have a lot of columns you could potentially do that via a collection but it may not be worth the extra effort.
The curr_sql string stays the same, all that's changing is that you're binding the actual value from the relevant rec1 column, rather than never-null string you were forming.
I am creating a package to use with Jasper reports where I learnt that I need SYS_REFCURSOR but I cannot seem to be able to Loop my cursors:eg
create or replace PACKAGE BODY fin_statement_spool
AS
PROCEDURE fin_main_spool(vacid in VARCHAR2, vfromdate in date, vtodate in date,c1 out SYS_REFCURSOR,c2 out SYS_REFCURSOR)
AS
cramount NUMBER;
dramount NUMBER;
countcr NUMBER;
countdr NUMBER;
BEGIN
OPEN c1 FOR
SELECT
.......;
OPEN c2 FOR
SELECT ........;
BEGIN
FOR i IN c1--Error is here
LOOP
rnum := 0;
cramount := 0;
dramount := 0;
countdr := 0;
countcr := 0;
..........
Isn't this the right way?
You appear to have confused explicit cursors, e.g.:
declare
cursor cur is
select dummy from dual;
begin
for rec in cur
loop
dbms_output.put_line(rec.dummy);
end loop;
end;
/
with a ref cursor - which is a pointer to an open cursor.
You would typically use a ref cursor to open a cursor in the db and pass it back to the calling app for it to loop through.
The way you have declared the ref cursors as out parameters and then tried to loop through them in the same procedure does not make sense - once you have fetched a record from a cursor, you cannot re-fetch it.
If you absolutely must loop through a ref cursor, you'd use this sort of syntax:
declare
cur sys_refcursor;
rec dual%rowtype;
begin
open cur for select dummy from dual;
loop
fetch cur into rec;
exit when cur%notfound;
dbms_output.put_line(rec.dummy);
end loop;
end;
/
but as I said, in general, you wouldn't be looping through ref cursors in the db, you'd be doing that in the calling code.
Perhaps if you updated your question with the requirements you're trying to fulfil, we could suggest a better way of doing it.
I struggle a problem, which, i think, is rather simple.
I have a type T_OPERATION_TAG in a database which is created as:
CREATE OR REPLACE TYPE t_operation_tag AS OBJECT(
tag_name VARCHAR2(30),
tag_value VARCHAR2(30),
CONSTRUCTOR FUNCTION t_operation_tag RETURN SELF AS RESULT
)
I also have another type T_OPERATION_TAGS, which is defined as follows
CREATE OR REPLACE TYPE t_operation_tags AS TABLE OF t_operation_tag;
Then in my pl/sql block i have the following code
DECLARE
p_op_tags t_operation_tags;
BEGIN
p_op_tags := t_operation_tags();
FOR i IN (SELECT tag_name, tag_value
FROM op_tags_table
WHERE some_condition)
LOOP
--How to append new lines to p_op_tags ?
END LOOP;
END;
So, if the SELECT-query in the FOR LOOP returns,e.g., five lines then how can I populate my P_OP_TAGS object table with these five lines?
Like this:
DECLARE
p_op_tags t_operation_tags;
p_cursor sys_refcursor;
p_limit number := 5;
BEGIN
open p_cursor for
SELECT t_operation_tag(tag_name, tag_value)
FROM op_tags_table
;
fetch p_cursor bulk collect into p_op_tags limit p_limit;
DBMS_OUTPUT.put_line(p_op_tags(4).tag_name);
close p_cursor;
END;
Or if you prefer the loop clause:
DECLARE
p_op_tag t_operation_tag;
p_op_tags t_operation_tags;
p_limit number := 5;
BEGIN
p_op_tags := t_operation_tags();
for i in (SELECT tag_name, tag_value
FROM op_tags_table
WHERE some_condition
and rownum < p_limit + 1)
loop
p_op_tag := t_operation_tag(i.tag_name, i.tag_value);
p_op_tags.extend();
p_op_tags(p_op_tags.COUNT) := p_op_tag;
end loop;
DBMS_OUTPUT.put_line(p_op_tags(4).tag_name);
END;
/
You don't really need a cursor or loop at all, if you're populating the collection entirely from your query; you can bulk collect straight into it:
DECLARE
p_op_tags t_operation_tags;
BEGIN
SELECT t_operation_tag(tag_name, tag_value)
BULK COLLECT INTO p_op_tags
FROM op_tags_table
WHERE some_condition;
...
END;
/
I am trying to run a stored procedure that has multiple in and out parameters. The procedure can only be viewed in my Connections panel by navigating
Other Users | <user> | Packages | <package> | <procedure>
If I right click , the menu items are "Order Members By..." and "Create Unit Test" (greyed out). The ability to "Run" the procedure does not seem possible when it's accessed by user.
I have been trying to find an example of how to create an anonymous block so that I can run the procedure as a SQL file, but haven't found anything that works.
Does anyone know how I can execute this procedure from SQL Developer? I am using Version 2.1.1.64.
EDIT 1:
The procedure I want to call has this signature:
user.package.procedure(
p_1 IN NUMBER,
p_2 IN NUMBER,
p_3 OUT VARCHAR2,
p_4 OUT VARCHAR2,
p_5 OUT VARCHAR2,
p_6 OUT NUMBER)
If I write my anonymous block like this:
DECLARE
out1 VARCHAR2(100);
out2 VARCHAR2(100);
out3 VARCHAR2(100);
out4 NUMBER(100);
BEGIN
EXECUTE user.package.procedure (33,89, :out1, :out2, :out3, :out4);
END;
I get the error:
Bind Varialbe "out1" is NOT DECLCARED
anonymous block completed
I've tried initializing the out* variables:
out1 VARCHAR2(100) := '';
but get the same error:
EDIT 2:
Based on Alex's answer, I tried removing the colons from in front of the params and get this:
Error starting at line 1 in command:
DECLARE
out1 VARCHAR2(100);
out2 VARCHAR2(100);
out3 VARCHAR2(100);
out4 NUMBER(100);
BEGIN
EXECUTE user.package.procedure (33,89, out1, out2, out3, out4);
END;
Error report:
ORA-06550: line 13, column 17:
PLS-00103: Encountered the symbol "USER" when expecting one of the following:
:= . ( # % ; immediate
The symbol ":=" was substituted for "USER" to continue.
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
With simple parameter types (i.e. not refcursors etc.) you can do something like this:
SET serveroutput on;
DECLARE
InParam1 number;
InParam2 number;
OutParam1 varchar2(100);
OutParam2 varchar2(100);
OutParam3 varchar2(100);
OutParam4 number;
BEGIN
/* Assign values to IN parameters */
InParam1 := 33;
InParam2 := 89;
/* Call procedure within package, identifying schema if necessary */
schema.package.procedure(InParam1, InParam2,
OutParam1, OutParam2, OutParam3, OutParam4);
/* Display OUT parameters */
dbms_output.put_line('OutParam1: ' || OutParam1);
dbms_output.put_line('OutParam2: ' || OutParam2);
dbms_output.put_line('OutParam3: ' || OutParam3);
dbms_output.put_line('OutParam4: ' || OutParam4);
END;
/
Edited to use the OP's spec, and with an alternative approach to utilise :var bind variables:
var InParam1 number;
var InParam2 number;
var OutParam1 varchar2(100);
var OutParam2 varchar2(100);
var OutParam3 varchar2(100);
var OutParam4 number;
BEGIN
/* Assign values to IN parameters */
:InParam1 := 33;
:InParam2 := 89;
/* Call procedure within package, identifying schema if necessary */
schema.package.procedure(:InParam1, :InParam2,
:OutParam1, :OutParam2, :OutParam3, :OutParam4);
END;
/
-- Display OUT parameters
print :OutParam1;
print :OutParam2;
print :OutParam3;
print :OutParam4;
Executing easy. Getting the results can be hard.
Take a look at this question I asked Best way/tool to get the results from an oracle package procedure
The summary of it goes like this.
Assuming you had a Package named mypackage and procedure called getQuestions. It returns a refcursor and takes in string user name.
All you have to do is create new SQL File (file new). Set the connection and paste in the following and execute.
var r refcursor;
exec mypackage.getquestions(:r, 'OMG Ponies');
print r;
For those using SqlDeveloper 3+, in case you missed that:
SqlDeveloper has feature to execute stored proc/function directly, and output are displayed in a easy-to-read manner.
Just right click on the package/stored proc/ stored function, Click on Run and choose target to be the proc/func you want to execute, SqlDeveloper will generate the code snippet to execute (so that you can put your input parameters). Once executed, output parameters are displayed in lower half of the dialog box, and it even have built-in support for ref cursor: result of cursor will be displayed as a separate output tab.
Open the procedure in SQL Developer and run it from there. SQL Developer displays the SQL that it runs.
BEGIN
PROCEEDURE_NAME_HERE();
END;
Use:
BEGIN
PACKAGE_NAME.PROCEDURE_NAME(parameter_value, ...);
END;
Replace "PACKAGE_NAME", "PROCEDURE_NAME", and "parameter_value" with what you need. OUT parameters will need to be declared prior to.
Though this question is quite old, I keep stumbling into same result without finding an easy way to run from sql developer.
After couple of tries, I found an easy way to execute the stored procedure from sql developer itself.
Under packages, select your desired package and right click on the package name (not on the stored procedure name).
You will find option to run. Select that and supply the required arguments. Click OK and you can see the output in output variables section below
I'm using SQL developer version 4.1.3.20
None of these other answers worked for me. Here's what I had to do to run a procedure in SQL Developer 3.2.20.10:
SET serveroutput on;
DECLARE
testvar varchar(100);
BEGIN
testvar := 'dude';
schema.MY_PROC(testvar);
dbms_output.enable;
dbms_output.put_line(testvar);
END;
And then you'd have to go check the table for whatever your proc was supposed to do with that passed-in variable -- the output will just confirm that the variable received the value (and theoretically, passed it to the proc).
NOTE (differences with mine vs. others):
No : prior to the variable name
No putting .package. or .packages. between the schema name and the procedure name
No having to put an & in the variable's value.
No using print anywhere
No using var to declare the variable
All of these problems left me scratching my head for the longest and these answers that have these egregious errors out to be taken out and tarred and feathered.
Can't believe, this won't execute in SQL Developer:
var r refcursor;
exec PCK.SOME_SP(:r,
'02619857');
print r;
BUT this will:
var r refcursor;
exec TAPI_OVLASCENJA.ARH_SELECT_NAKON_PRESTANKA_REG(:r, '02619857');
print r;
Obviously everything has to be in one line..
Using SQL Developer Version 4.0.2.15 Build 15.21 the following works:
SET SERVEROUTPUT ON
var InParam1 varchar2(100)
var InParam2 varchar2(100)
var InParam3 varchar2(100)
var OutParam1 varchar2(100)
BEGIN
/* Assign values to IN parameters */
:InParam1 := 'one';
:InParam2 := 'two';
:InParam3 := 'three';
/* Call procedure within package, identifying schema if necessary */
schema.package.procedure(:InParam1, :InParam2, :InParam3, :OutParam1);
dbms_output.enable;
dbms_output.put_line('OutParam1: ' || :OutParam1);
END;
/
To run procedure from SQL developer-only execute following command
EXECUTE PROCEDURE_NAME;
I had a stored procedure that returned a cursor, in my case it was actually of a custom package type (T_CURSOR, looks like a convention to me) that is defined as REF CURSOR.
There may be a better way to do this, but I defined variables for all the columns of the table that the cursor was iterating, looped the cursor fetching each row into those variables, then printed them out.
SET serveroutput on;
DECLARE
testvar number;
v_cur SYS_REFCURSOR;
ORIGINAL_EMP_NUM NUMBER;
TEMPORARY_EMP_NUM NUMBER;
ORG_UNIT_CODE VARCHAR2(2 BYTE);
MRU_CODE VARCHAR2(10 BYTE);
CTRL_COMPANY_CODE VARCHAR2(10 BYTE);
IS_TEMP_FLAG VARCHAR2(1 BYTE);
BEGIN
testvar := 420;
foo.updates.get_temporary_authorisations(testvar, v_cur);
dbms_output.enable;
dbms_output.put_line(testvar);
LOOP
FETCH v_cur INTO ORIGINAL_EMP_NUM, TEMPORARY_EMP_NUM, ORG_UNIT_CODE, MRU_CODE, CTRL_COMPANY_CODE, IS_TEMP_FLAG;
EXIT WHEN v_cur%NOTFOUND;
dbms_output.put_line(ORIGINAL_EMP_NUM || ',' || TEMPORARY_EMP_NUM || ',' || ORG_UNIT_CODE || ',' || MRU_CODE|| ',' || CTRL_COMPANY_CODE|| ',' || IS_TEMP_FLAG);
END LOOP;
CLOSE v_cur;
END;
I wasn't able to get #Alex Poole answers working. However, by trial and error, I found the following works (using SQL Developer version 3.0.04). Posting it here in case it helps others:
SET serveroutput on;
DECLARE
var InParam1 number;
var InParam2 number;
var OutParam1 varchar2(100);
var OutParam2 varchar2(100);
var OutParam3 varchar2(100);
var OutParam4 number;
BEGIN
/* Assign values to IN parameters */
InParam1 := 33;
InParam2 := 89;
/* Call procedure within package, identifying schema if necessary */
schema.package.procedure(InParam1, InParam2,
OutParam1, OutParam2, OutParam3, OutParam4);
/* Display OUT parameters */
dbms_output.put_line('OutParam1: ' || OutParam1);
dbms_output.put_line('OutParam2: ' || OutParam2);
dbms_output.put_line('OutParam3: ' || OutParam3);
dbms_output.put_line('OutParam4: ' || OutParam4);
END;
--for setting buffer size needed most of time to avoid `anonymous block completed` message
set serveroutput on size 30000;
-- declaration block in case output need to catch
DECLARE
--declaration for in and out parameter
V_OUT_1 NUMBER;
V_OUT_2 VARCHAR2(200);
BEGIN
--your stored procedure name
schema.package.procedure(
--declaration for in and out parameter
V_OUT_1 => V_OUT_1,
V_OUT_2 => V_OUT_2
);
V_OUT_1 := V_OUT_1;
V_OUT_2 := V_OUT_2;
-- console output, no need to open DBMS OUTPUT seperatly
-- also no need to print each output on seperat line
DBMS_OUTPUT.PUT_LINE('Ouput => ' || V_OUT_1 || ': ' || V_OUT_2);
END;
Creating Pl/SQL block can be painful if you have a lot of procedures which have a lot of parameters. There is an application written on python that do it for you.
It parses the file with procedure declarations and creates the web app for convenient procedure invocations.
var out_para_name refcursor;
execute package_name.procedure_name(inpu_para_val1,input_para_val2,... ,:out_para_name);
print :out_para_name;
If I have a function which returns a reference cursor for a query, how can I view the result set of this in SQL Developer? Toad has a special tab for viewing the results of a reference cursor, this is the functionality I would like to find.
SET SERVEROUTPUT ON;
VARIABLE X REFCURSOR;
EXEC PROCEDURE_WITH_OUTPUT_SYS_REFCURSOR(:X);
PRINT X;
Double click the cursor fields in your result record. On the right side there is a "..." icon. Click this and you'll see the contents
Hi I know this was asked a while ago but I've just figured this out and it might help someone else. Not sure if this is exactly what you're looking for but this is how I call a stored proc and view the output in SQL Developer.
In SQL Developer when viewing the proc, right click and choose 'Run' or select Ctrl+F11 to bring up the Run PL/SQL window. This creates a template with the input and output params which you need to modify. To return the results of a sys_refcursor you then need to declare a row type that is exactly equivalent to the select stmt / sys_refcursor being returned by the proc. Below I declare "type t_row" which matches my output fields, then loop through the returned sys_refcursor. If t_row matches my sys_refcursor then it gets populated with each row of the sys_refcursor:
DECLARE
P_CAE_SEC_ID_N NUMBER;
P_FM_SEC_CODE_C VARCHAR2(200);
P_PAGE_INDEX NUMBER;
P_PAGE_SIZE NUMBER;
v_Return sys_refcursor;
type t_row is record (CAE_SEC_ID NUMBER,FM_SEC_CODE VARCHAR2(7),rownum number, v_total_count number);
v_rec t_row;
BEGIN
P_CAE_SEC_ID_N := NULL;
P_FM_SEC_CODE_C := NULL;
P_PAGE_INDEX := 0;
P_PAGE_SIZE := 25;
CAE_FOF_SECURITY_PKG.GET_LIST_FOF_SECURITY(
P_CAE_SEC_ID_N => P_CAE_SEC_ID_N,
P_FM_SEC_CODE_C => P_FM_SEC_CODE_C,
P_PAGE_INDEX => P_PAGE_INDEX,
P_PAGE_SIZE => P_PAGE_SIZE,
P_FOF_SEC_REFCUR => v_Return
);
-- Modify the code to output the variable
-- DBMS_OUTPUT.PUT_LINE('P_FOF_SEC_REFCUR = ');
loop
fetch v_Return into v_rec;
exit when v_Return%notfound;
DBMS_OUTPUT.PUT_LINE('sec_id = ' || v_rec.CAE_SEC_ID || 'sec code = ' ||v_rec.FM_SEC_CODE);
end loop;
END;
there are no way to display a refcursor in datagrid in sqldeveloper.
we can define a refcursor,call SP,then print refcursor,then data will be printed in Script output window in a plane text mode,but not in Query Result window.