Following Sergey's example here, https://stackoverflow.com/a/60834163/1513027
I'm trying to create an anonymous DO block rather than a function.
If I have the FETCH inside the block, it gives a syntax error, possibly wanting an INTO clause.
And it doesn't matter whether the name of the cursor is in quotes.
DO
$$
DECLARE _query TEXT;
DECLARE _cursor CONSTANT refcursor := _cursor;
BEGIN
_query := 'select "Port", "Version", "AddDate" from "LatestLogEntry";';
OPEN _cursor FOR EXECUTE _query;
FETCH ALL FROM _cursor; -- syntax error at ;
END
$$;
If I have it outside, as in Sergey's example, then it can't see the cursor declared inside the block. And it does matter whether the name of the cursor is in quotes.
DO
$$
DECLARE _query TEXT;
DECLARE _cursor CONSTANT refcursor := '_cursor';
BEGIN
_query := 'select "Port", "Version", "AddDate" from "LatestLogEntry";';
OPEN _cursor FOR EXECUTE _query;
END
$$;
FETCH ALL FROM _cursor -- ERROR: cursor "_cursor" does not exist
The answer was hidden in a comment in one of the examples.
-- need to be in a transaction to use cursors.
Wrapping it in a transaction works.
BEGIN;
DO
$$
DECLARE _query TEXT;
DECLARE _cursor CONSTANT refcursor := '_cursor';
BEGIN
_query := 'select "Port", "Version", "AddDate" from "LatestLogEntry";';
OPEN _cursor FOR EXECUTE _query;
END
$$;
FETCH ALL FROM _cursor -- ERROR: cursor "_cursor" does not exist
COMMIT
In pgadmin this does work see screen below run postgres 15
as Sergey pointed out this has to be in a transaction, else you get the error message you get.
you can try to use it in an tranction
Related
As part of a test I want to run a PL/SQL block using EXECUTE IMMEDIATE but when I try to fetch the result with INTO it always returns the same error regardless the content of the PL/SQL block I want to run.
DECLARE
l_output VARCHAR2(10);
BEGIN
EXECUTE IMMEDIATE 'BEGIN COMMIT; END;' INTO l_output;
END;
/
And the error is
ORA-01007: variable not in select list
I know this error has to with l_output not being the same type as the returning type by EXECUTE IMMEDIATE, but I don't know the type. I already tried to change l_output to CLOB, BLOB, NUMBER and nothing changes. Any idea?
OK, this is another example, same result.
DECLARE
l_output VARCHAR2(10);
BEGIN
EXECUTE IMMEDIATE 'BEGIN DBMS_OUTPUT.PUT_LINE(''TEST''); END;' INTO l_output;
END;
/
Oracle is complaining because your PL/SQL does not return anything for it to store in l_output. What are you expecting the value of l_output to be?
One would use EXECUTE IMMEDIATE...INTO with something like this to return a value from a PL/SQL block.
DECLARE
l_output VARCHAR2(10);
BEGIN
EXECUTE IMMEDIATE 'SELECT ''ABC'' FROM DUAL' INTO l_output;
dbms_output.put_line('l_output = ' || l_output);
END;
/
UPDATE
If you want, you can do this:
DECLARE
l_output VARCHAR2(10);
BEGIN
EXECUTE IMMEDIATE 'BEGIN :1 := 5; END;' USING IN OUT l_output;
dbms_output.put_line('l_output = ' || l_output);
END;
I need to get a table of bank's name which their bsb is equal to value given to the function.
Here is my code:
CREATE OR REPLACE Function FF(BSB_NUMBER IN BANK.BSB#%TYPE) RETURN SYS_REFCURSOR
IS
MY_CURSOR SYS_REFCURSOR;
BEGIN
OPEN MY_CURSOR for
select * from bank where bank.bsb# = BSB_NUMBER;
return MY_CURSOR;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Error ! There is no such account');
END FF;
/
And I run in with this but doesn't print anything. Appreciate any idea:
SELECT FindBankStaff(012878) FROM BANK;
Don't return the cursor, return the appropriate value.
Finally I saw this answer and implement it to my issue:
CREATE OR REPLACE FUNCTION SOME_FUNC_RETURNING_A_CURSOR RETURN SYS_REFCURSOR IS
csrLocal SYS_REFCURSOR;
BEGIN
OPEN csrLocal FOR SELECT NAME, BSB# FROM BANK;
RETURN csrLocal;
END SOME_FUNC_RETURNING_A_CURSOR;
/
DECLARE
aCursor SYS_REFCURSOR;
someVariable VARCHAR2(40);
some2 number;
BEGIN
aCursor := SOME_FUNC_RETURNING_A_CURSOR;
WHILE TRUE LOOP
FETCH aCursor INTO someVariable,some2;
EXIT WHEN aCursor%NOTFOUND;
DBMS_OUTPUT.PUT(someVariable);
DBMS_OUTPUT.PUT(' ');
DBMS_OUTPUT.PUT_LINE(some2);
END LOOP;
COMMIT;
END;
/
In Toad there is an option to do this.
You just have to create a bind variable as Ref cursor and invoke the procedure or function. Once the process runs successfully, the Data Grid is automatically populated with the result set of the Object (In your case the records from ref cursor). I suppose even in Oracle Sql Developer the Feature has been incorporated.
If you are using SQL Plus* then the best way is to declare a variable as ref cursor. Execute the piece of block and print the output using print command. Hope it helps...
Is there a way to reuse the cursor declaration in postgres.
For example :
I have a function like below, I am trying to use the declaration of curs1 for curs2 is it possible ?
create or replace function vin_temp_test(k date,x varchar) RETURNS numeric[] AS $$
declare
curs1 CURSOR FOR select prod_name,sum(item_val) sum_value from temp_table group by prod_name;
curs2 cursor curs1;
begin
null
end;
$$ LANGUAGE plpgsql VOLATILE;
Directly it is not possible
but you can simplify code by using views
you can use dynamic unbound queries
DECLARE
c1 refcursor;
c2 refcursor;
sqlstr text;
BEGIN
sqlstr := 'SELECT ... ';
OPEN c1 FOR EXECUTE sqlstr;
OPEN c2 FOR EXECUTE sqlstr;
Important question is - what do you mean 'reuse a cursor'"?
Maybe you can use scrollable cursor with possible reset
There is a statement MOVE
MOVE FIRST IN curs1 -- reset cursor curs1
see http://www.postgresql.org/docs/9.3/static/plpgsql-cursors.html
I have an SQL procedure, that should execute a FOR-IN (SELECT ..) loop, where the SELECT content should vary depending on some input parameters. My idea was to store the SELECT string into a variable, and then try to extract the variable value in the FOR-IN loop but without success so far (earlier there was a fix SELECT statement used there, that's what I am trying to replace now). The code looks about as follows
PROCEDURE run(p_boolean BOOLEAN)
IS
BEGIN
DECLARE
v_mystring VARCHAR(50);
BEGIN
IF p_boolean = TRUE
THEN
v_mystring := 'SELECT something...';
ELSE
v_mystring := 'SELECT something else...';
END IF;
FOR p_table_name IN (would-like-to-use-the-value-of-v_mystring-here-some-way)
LOOP
...
END LOOP;
END;
END;
Being quite novice in SQL, it might well happen that the entire concept of trying to use a string variable value here is wrong. I browsed through some tutorials and tried some other ideas (e.g. cursor), but no result. Any idea is appreciated
Assuming Oracle's PL/SQL ,You can open a REFCURSOR using dynamic String and call it in a LOOP..
PROCEDURE run(p_boolean BOOLEAN)
IS
BEGIN
DECLARE
v_mystring VARCHAR(50);
v_my_ref_cursor sys_refcursor;
BEGIN
IF p_boolean = TRUE
THEN
v_mystring := 'SELECT something...';
ELSE
v_mystring := 'SELECT something else...';
END IF;
OPEN v_my_ref_cursor FOR v_mystring;
LOOP
FETCH v_my_ref_cursor INTO your_variables/record
EXIT WHEN v_my_ref_cursor%NOTFOUND;
..
END LOOP;
CLOSE v_my_ref_cursor;
END;
END;
I am attempting to get a ref cursor to run a dynamic query and return the results. here is an example of what I'm trying to do:
DECLARE
TYPE CUR_DATA IS REF CURSOR;
OUT_DATA CUR_DATA;
SQL_Statement NVARCHAR2(8000);
BEGIN
SQL_Statement := ' SELECT * FROM dual ';
OPEN OUT_DATA FOR SQL_Statement;
END;
why does this give me an error saying : expression is of wrong type? This ref cursor is weakly typed isn't it? Help!
It is mentioned in the Oracle document that the Select Statement support CHAR, VARCHAR2, or CLOB (not NCHAR or NVARCHAR2).
If you want to implement with NVARCHAR then the only solution i know is to translate USING CHAR_CS argument converts char into the database character set. The output datatype is VARCHAR2.
DECLARE
TYPE CUR_DATA IS REF CURSOR;
OUT_DATA CUR_DATA;
SQL_Statement NVARCHAR2(4000); --declare this as VARCHAR2
SQL_Statement_var VARCHAR2(4000);
BEGIN
SQL_Statement := N'SELECT * FROM dual ';
SQL_Statement_var := TRANSLATE(SQL_Statement USING CHAR_CS);
OPEN OUT_DATA FOR SQL_Statement_var;
END;
No errors.
If NVARCHAR2 is not mandatory ,then try to create with basic data types provided.
DECLARE
TYPE CUR_DATA IS REF CURSOR;
OUT_DATA CUR_DATA;
SQL_Statement VARCHAR2(4000); --declare this as VARCHAR2
BEGIN
SQL_Statement := ' SELECT * FROM dual ';
OPEN OUT_DATA FOR SQL_Statement;
END;
References:
Translate...USING
Open For Statement