I am having trouble testing this simple stored procedure in Oracle Sql Developer. The stored procedure does a simple select and returns a cursor.
create or replace
PROCEDURE GET_PROJECT_DRF_HISTORY
( projectId IN NUMBER,
resultset_out OUT sys_refcursor
) AS
BEGIN
OPEN resultset_out for
SELECT * from GLIDE_HISTORY
where GLIDE_HISTORY.PRJ_ID = projectId;
/* DBMS_OUTPUT.PUT_LINE(resultset_out);*/
END GET_PROJECT_DRF_HISTORY;
To test this procedure, I used the below script:
variable results sys_refcursor;
exec get_project_drf_history(3345, :results);
print :results;
Being new to both oracle and the Sql Developer tool, I am struggling to understand what is the mistake here. I cannot check this in Sql*Plus because I dont have the password to do so. I am using Oracle Sql Developer 1.1.2.25 and Oracle 10g.
Can anybody help me out please? Thank you in advance.
Sammy,
The variable declaration should be refcursor instead of sys_refcursor.
Also when you print the results, you are printing the variable itself, so there is no need for a : (which is used to indicateit is a bind variable).
I was able to run the following script sucessfully in SQL Developer (and of course sql plus.)
For SQL Developer, run it as a script using F5.
--Creating Procedure
create or replace procedure test_ref(
i_limit number,
o_results out sys_refcursor
) is
begin
open o_results for
'select object_name
from all_objects
where rownum < ' || i_limit;
end;
/
And then the script that calls this procedure. (excute as a script using F5).
var c1 refcursor;
exec test_ref(10,:c1);
print c1;
here is a working example, declare the refcursor then assign the value by calling you proc in an anonymous block.
then you print it
var x REFCURSOR ;
declare
/*a no cleanup procedure*/
procedure GetMeMyRefCursor(outter out nocopy sys_refcursor)
as
begin
open outter for
select level
from dual
connect by level <= 5;
end GetMeMyRefCursor;
begin
GetMeMyRefCursor(:x);
/*note you pass in the refcursor you created via the :X*/
end ;
/
print x;
/*now print it*/
/*LEVEL
----------------------
1
2
3
4
5*/
based on comment:
now using your comment, you are having an issue with IN/OUT params and not with the print (didn't read the title just the question and the other response)
this works: (based on your code)
create or replace
PROCEDURE GET_PROJECT_DRF_HISTORY
( projectId IN NUMBER,
resultset_out OUT sys_refcursor
) AS
BEGIN
OPEN resultset_out for
SELECT level from dual connect by level <= projectId;
/* DBMS_OUTPUT.PUT_LINE(resultset_out);*/
END GET_PROJECT_DRF_HISTORY;
/
var results REFCURSOR;
--this needs to be REFCURSOR (at least in 10g and 11i)
exec GET_PROJECT_DRF_HISTORY(5, :results);
print results;
/
You can also debug packages and procedures directly from SQL Developer (this can be a real life saver)
if you want to debug in SQL Developer it is really easy:
in the connections->your schema here-->procedures -> GET_PROJECT_DRF_HISTORY right click and 'Compile for debug'. Then in the procedure place a break point in it, then right click and 'debug' it (this will create an anonymous block -- see below -- where you can put in your values and such)
DECLARE
PROJECTID NUMBER;
RESULTSET_OUT sys_refcursor;
BEGIN
PROJECTID := NULL;
GET_PROJECT_DRF_HISTORY(
PROJECTID => PROJECTID,
RESULTSET_OUT => RESULTSET_OUT
);
-- Modify the code to output the variable
-- DBMS_OUTPUT.PUT_LINE('RESULTSET_OUT = ' || RESULTSET_OUT);
END;
(http://www.oracle.com/technetwork/developer-tools/sql-developer/sqldeveloperwhitepaper-v151-130908.pdf page 11)
otherwise, the error doesn't look as it should appear if you are doing this all from Developer.
But what I really think is happening is your VAR is incorrect and thus it doesn't exists!
variable results sys_refcursor;
Usage: VAR[IABLE] [ <variable> [ NUMBER | CHAR | CHAR (n [CHAR|BYTE]) |
VARCHAR2 (n [CHAR|BYTE]) | NCHAR | NCHAR (n) |
NVARCHAR2 (n) | CLOB | NCLOB | REFCURSOR |
BINARY_FLOAT | BINARY_DOUBLE ] ]
so, going from my initial example "var x REFCURSOR ;" should work
I recommend asking your administrator to upgrade your SQL Developer version. Yours is significantly outdated and you may be running into some obscure bugs. (I did when I tried to use version 1) You should be on 2.1 by now.
Related
I am trying to pass in a SQL string to a stored procedure and using EXECUTE IMMEDIATE to return the results. Something like this:
CREATE PROCEDURE P360_RCT_COUNT (sqlString IN VARCHAR2)
AS
BEGIN
EXECUTE IMMEDIATE sqlString;
END;
/
I am not sure how to accomplish it. With the above, when I execute the SP using the command below, I get an error:
EXECUTE P360_RCT_COUNT 'SELECT COUNT(DISTINCT ENTITY_ID),ADDR_COUNTY FROM P360_V_RCT_COUNT GROUP BY ADDR_COUNTY';
The error is: ORA-06550: line 1, column 22:
PLS-00103: Encountered the symbol "SELECT COUNT(ENTITY_ID),ADDR_COUNTY
FROM P360_V_RCT_COUNT GROUP " when expecting one of the following:
:= . ( # % ; The symbol ":=" was substituted for "SELECT
COUNT(DISTINCT ENTITY_ID),ADDR_COUNTY FROM P360_V_RCT_COUNT GROUP " to
continue.
Basically I am building a SQL string in a system and need to pass it in to the SP and get the results back to the system. I am relatively new to stored procedures in Oracle.
The easiest way to work with a result set is sys_refcursor. This can be used quite easily with JDBC or ODBC.
Your procedure would look like this:
CREATE PROCEDURE P360_RCT_COUNT (
sqlString IN VARCHAR2
, p_result_set out sys_refcursor)
AS
BEGIN
open p_result_set for sqlString;
END;
/
Obviously the precise details of how you call it will vary according to your client. But in SQL*Plus it would be:
var rc refcursor
exec P360_RCT_COUNT( 'SELECT COUNT(DISTINCT ENTITY_ID),ADDR_COUNTY FROM P360_V_RCT_COUNT GROUP BY ADDR_COUNTY', :rc);
print rc
To return lists of values in a OUT parameter you need to decide the type(s) to use.
Say, for example, you have to return some varchar2 and some date lists, you could use something like this:
create or replace type tabOfVarchar2 is table of varchar2(100);
create or replace type tabOfDates is table of date;
create or replace procedure testProc(pString IN varchar2,
pOutVarchar1 OUT tabOfVarchar2,
pOutVarchar2 OUT tabOfVarchar2,
pOutVarchar3 OUT tabOfVarchar2,
pOutDates OUT tabOfDates
) is
begin
execute immediate pString
bulk collect into pOutVarchar1, pOutVarchar2, pOutVarchar3, pOutDates;
end;
This is way you can test this procedure:
declare
v1 tabOfVarchar2 ;
v2 tabOfVarchar2;
v3 tabOfVarchar2;
d1 tabOfDates ;
vSQL varchar2(100) := 'select ''a'', ''b'', ''c'', sysdate from dual';
begin
testProc(vSQL, v1, v2, v3, d1);
--
for i in v1.first .. v1.last loop
dbms_output.put_line(v1(i) || '/' || v2(i) || '/' || v3(i) || '/' || to_char(d1(i), 'dd/mm/yyyy'));
end loop;
end;
which gives:
a/b/c/14/04/2017
This only works with queries that give exactly a fixed number of columns, of known types.
I have a table in an Oracle 12c databse called testimonial that has content as a column. I have created a stored search procedure to find testimonials whose content matches an input string that is defined as:
CREATE OR REPLACE PROCEDURE Search_Testimonials
(keyword IN VARCHAR2,
output OUT SYS_REFCURSOR)
AS
BEGIN OPEN output
FOR SELECT *
FROM Testimonial T
WHERE T.content LIKE keyword;
END;
/
VAR output REFCURSOR;
DECLARE
keyword VARCHAR2(15) := '%like%';
BEGIN
Search_Testimonials(keyword, :output);
END;
/
I am trying to run a test on this procedure using the input 'like'. From what I have found on this site and other sites I should run the following:
var output refcursor;
exec Search_Testimonials('like', output);
print output;
However my output is just:
OUTPUT
------
When it should display all the records in testimonial table as they all contain the word 'like.'
Am I messing up something in the procedure? I've looked around and this seems to be how to do it as far as I can figure. Thanks!
I have a question about calling a procedure in Oracle.
This is what I have and this works fine in SQLPlus.
VARIABLE resultSet REFCURSOR;
BEGIN
CALL_TEST('10DD', :resultSet);
END;
/
But, the code below doesn't work because it gives me the explanation of the variable instead of saying "PL/SQL procedure successfully completed."
VARIABLE resultSet REFCURSOR; BEGIN HUGHES_ARIAL.DUNNING_TEST('1D10', :resultSet); END; /
The issue is I need to press enter after every ; (semicolon). Is there a way to make my statement above to work with just 1 line without having to press enter?
I am using an email campaign enterprise software, but it doesn't allow me to do what I can do in SQLPlus.
All SQL*Plus commands should be within one line. When clubbing different commands, it has to be in multiple lines.
Example:
SQL> variable test NUMBER;set linesize 0;
Usage: VAR[IABLE] [ <variable> [ NUMBER | CHAR | CHAR (n [CHAR|BYTE]) |
VARCHAR2 (n [CHAR|BYTE]) | NCHAR | NCHAR (n) |
NVARCHAR2 (n) | CLOB | NCLOB | REFCURSOR |
BINARY_FLOAT | BINARY_DOUBLE ] ]
Your Procedure can be invoked this way, using EXEC.
VARIABLE resultSet REFCURSOR;
EXEC CALL_TEST('10DD', :resultSet);
OR
VARIABLE resultSet REFCURSOR;
BEGIN CALL_TEST('10DD', :resultSet); END;
/
Your entire PL/SQL block may be in one line, where-as when attempted to execute, you have to explicitly specify the '/' as a new line!
If you are concern in running in multiple lines,
Put it in a file and run as Script.
SQL> !cat my_script.sql
VARIABLE resultSet REFCURSOR;
BEGIN
CALL_TEST('10DD', :resultSet);
END;
/
SQL> start my_script.sql
I am using Postgresql 8.3 and have the following simple function that will return a refcursor to the client
CREATE OR REPLACE FUNCTION function_1() RETURNS refcursor AS $$
DECLARE
ref_cursor REFCURSOR;
BEGIN
OPEN ref_cursor FOR SELECT * FROM some_table;
RETURN (ref_cursor);
END;
$$ LANGUAGE plpgsql;
Now , I can use the following SQL commands to call this function and manipulate the returned cursor ,but the cursor name is automatically generated by the PostgreSQL
BEGIN;
SELECT function_1(); --It will output the generated cursor name , for example , "<unnamed portal 11>" ;
FETCH 4 from "<unnamed portal 11>";
COMMIT;
Besides explicitly declaring the cursor name as the input parameter of the function as described by 38.7.3.5. Returning Cursors, can I declare my own cursor name and use this cursor name to manipulate the returned cursor instead of Postgresql automatically generates for me ?
If not, are there any commands that can get the generated cursor name ?
I'm not quite sure from wich version of Postgre this is available (in 8.4 it is valid) but i found quite easiest to define the cursor name when you declare it, like this:
CREATE OR REPLACE FUNCTION function_1() RETURNS refcursor AS $$
DECLARE
ref_cursor REFCURSOR := 'mycursor';
BEGIN
OPEN ref_cursor FOR SELECT * FROM some_table;
RETURN (ref_cursor);
END;
$$ LANGUAGE plpgsql;
And then you can get it like this:
BEGIN;
SELECT function_1();
FETCH 4 from mycursor;
COMMIT;
I find this method less cumbersome.
Hope that helps.
Yes, use:
CREATE OR REPLACE FUNCTION function_1(refcursor) RETURNS refcursor AS $$
BEGIN
OPEN $1 FOR SELECT * FROM some_table;
RETURN $1;
END;
$$ LANGUAGE plpgsql;
Result:
SELECT function_1('myowncursorname');
function_1
-----------------
myowncursorname
(1 row)
It looks like auto-generated name is <unnamed portal n>, where n is natural number (from 1).
EDIT:
As another way you could use pg_cursors view with such query to obtain generated cursor name:
SELECT name FROM pg_cursors WHERE statement LIKE 'SELECT * FROM some_table';
For example:
BEGIN;
SELECT function_1();
SELECT name FROM pg_cursors WHERE statement LIKE 'SELECT * FROM some_table';
COMMIT;
Result:
function_1
--------------------
<unnamed portal 3>
(1 row)
name
--------------------
<unnamed portal 3>
(1 row)
I'm attempting to write a stored proc that takes in a number, n, and returns the first n results for a given query, exclusively locking those n rows. I'm a little new to SQL and I'm having a bit of difficulty matching data types correctly.
My package spec looks like this:
PACKAGE package IS
Type out_result_type is REF CURSOR;
PROCEDURE stored_proc
(in_n IN NUMBER DEFAULT 10,
out_list IN OUT out_result_type);
I then define the cursor in the procedure body, like so:
CURSOR OUT_RESULT_TYPE IS
SELECT a.id
FROM schema.table a
WHERE (some conditions) AND rownum <= in_n;
A bit later on I then try to extract the results of the cursor into the output variable:
OPEN OUT_RESULT_TYPE;
FETCH OUT_RESULT_TYPE INTO out_list; -- error on this line
CLOSE OUT_RESULT_TYPE;
But alas this code doesn't compile; oracle complains that out_list has already been defined with a conflicting data type. Any idea how I can resolve this issue? It's driving me crazy!
Thanks in advance.
CREATE OR REPLACE PACKAGE pkg_test
AS
TYPE tt_cur IS REF CURSOR;
PROCEDURE prc_cur (retval OUT tt_cur);
END;
CREATE OR REPLACE PACKAGE BODY pkg_test
AS
PROCEDURE prc_cur (retval OUT tt_cur)
AS
BEGIN
OPEN retval
FOR
SELECT *
FROM dual;
END;
END;
If you want to lock, use:
CREATE OR REPLACE PACKAGE BODY pkg_test
AS
PROCEDURE prc_cur (retval OUT tt_cur)
AS
BEGIN
OPEN retval
FOR
SELECT a.id
FROM schema.table a
WHERE (some conditions)
AND rownum <= in_n
ORDER BY
column
-- Never forget ORDER BY!
FOR UPDATE;
END;
END;
Two remarks:
A cursor doesn't lock.
You don't have to do Type out_result_type is REF CURSOR;, use default type sys_refcursor. See here: Oracle - How to have an out ref cursor parameter in a stored procedure?
Your out_list must be of wrong type. Consider (script run on 10.2.0.3):
CREATE TABLE t AS SELECT ROWNUM ID FROM all_objects WHERE ROWNUM <= 100;
CREATE OR REPLACE PACKAGE cursor_pck AS
TYPE out_result_type is REF CURSOR;
PROCEDURE stored_proc (p_in IN NUMBER DEFAULT 10,
p_out_list IN OUT out_result_type);
END cursor_pck;
/
If you want to select and lock the rows at the same time you would use the FOR UPDATE clause:
CREATE OR REPLACE PACKAGE BODY cursor_pck AS
PROCEDURE stored_proc (p_in IN NUMBER DEFAULT 10,
p_out_list IN OUT out_result_type) IS
BEGIN
OPEN p_out_list FOR SELECT a.id FROM t a WHERE ROWNUM <= p_in FOR UPDATE;
END stored_proc;
END cursor_pck;
/
With the following setup, you will call the procedure like this:
SQL> SET SERVEROUTPUT ON;
SQL> DECLARE
2 l_cursor cursor_pck.out_result_type;
3 l_id t.id%TYPE;
4 BEGIN
5 cursor_pck.stored_proc(3, l_cursor);
6 LOOP
7 FETCH l_cursor INTO l_id;
8 EXIT WHEN l_cursor%NOTFOUND;
9 dbms_output.put_line(l_id);
10 END LOOP;
11 END;
12 /
1
2
3
PL/SQL procedure successfully completed
This is not going to work the way it's written, because
out_list expects a cursor, not a cursor result.
The name out_result_type is already used for a type, so you can't redefine it to be a cursor in the same scope.
Oracle provides a pre-defined weak reference cursor: sys_refcursor. In usage it would look like:
CREATE OR REPLACE PACKAGE pkg_test
AS
PROCEDURE prc_cur (p_retval OUT sys_refcursor,
p_lookup IN VARCHAR2);
END pkg_test;
CREATE OR REPLACE PACKAGE BODY pkg_test
AS
PROCEDURE prc_cur(p_retval OUT sys_refcursor
p_lookup IN VARCHAR2)
IS
BEGIN
OPEN retval FOR SELECT a.value
FROM tblname a
WHERE a.id <= p_lookup;
END prc_cur;
END pkg_test;
This saves you the trouble of needing to declare a type. The sys_refcursor is a pointer to a result set from an open cursor. If you are familiar with Java, it's the same concept as the java.sql.ResultSet object which provides a way to get at the results of a query.