How to return a CTE as REFCURSOR from an Oracle stored procedure?
-
16-10-2019 - |
Question
I tried to modify an Oracle stored procedure to use a CTE instead of a simple Select Statement.
My procedure looked like this:
Create or replace Myproc ( MyRefCursor IN OUT SYS_REFCURSOR)
as
begin
Open MyRefCursor for
Select * from ...something ...;
end;
/
I rewrote this query:
Select * from ...something ...;
As this CTE:
with MyCTE As (
... ;
)
Select * from MyCTE;
Opening a cursor this way does not work:
Open MyRefCursor for
with MyCTE As (
... ;
)
Select * from MyCTE;
Nor does this:
with MyCTE As (
... ;
)
Open MyRefCursor for
Select * from MyCTE;
Solution
Since the CTE is part of the same SQL statement, it should not contain a semicolon.
So, there should be no semicolon on the second line of the third block or the third line of the fourth block. The fifth block does not have a contiguous SQL statement.
OTHER TIPS
A complete very basic example using a stored procedure without input parameter:
Some demo data:
CREATE TABLE DEMO(
id NUMBER(10),
type NUMBER(10),
code varchar2(20)
);
Insert INTO DEMO values (1, 0, 'a');
Insert INTO DEMO values (2, 0, 'b');
Insert INTO DEMO values (3, 0, 'c');
Insert INTO DEMO values (4, 1, 'd');
Insert INTO DEMO values (5, 1, 'e');
Insert INTO DEMO values (6, 1, 'f');
SELECT * from DEMO;
Now a simple stored procedure using a trivial CTE:
create or replace procedure return_from_simple_cte
(
MyRefCursor IN OUT SYS_REFCURSOR
)
AS
BEGIN
Open MyRefCursor for
WITH My_CTE AS(
SELECT * FROM DEMO WHERE Type = 1
)
Select * FROM My_CTE;
END;
/
And finally a test call for sqlplus or TOAD
VAR R REFCURSOR
EXEC return_from_simple_cte (:R)
PRINT r
Background to this question:
I did the transformation of the Select-statement to CTE on SQL-Server an I wanted to add row-numbers to the result. I simply forget that add an alias to the *
create or replace PROCEDURE TEChange
(
MyRefCursor IN OUT SYS_REFCURSOR
,p_TERefnr NUMBER
)
AS
BEGIN
Open MyRefCursor for
WITH TE_CTE AS (
SELECT TeRefnr
FROM vSYSTE
WHERE TERefnr <> p_TERefnr
)
Select
ROW_NUMBER() over(order by TERefnr) Nr,
t.*
from TE_CTE t;
END;
/
nonreursive CTEs seem to help to migrate from SQL-Server to Oracle, but there are some minor syntax differences.