Escolar Documentos
Profissional Documentos
Cultura Documentos
0down
vote 1) Make sure you are using SYS_REFCURSOR.
2) Create your function like below in DB:
CREATE OR REPLACE FUNCTION FUNC1 (P1 VARCHAR2) RETURN SYS_REFCURSOR IS
XDO_CURSOR SYS_REFCURSOR;
BEGIN
IF P1 = 'USA' THEN
OPEN XDO_CURSOR FOR
'SELECT TO_CHAR(SYSDATE,''MM-DD-YYYY'') AS CURRENT_DATE, X.STATE FROM
schemaName.XX1 X WHERE X.ID IN (100,200,400)';
RETURN XDO_CURSOR;
ELSE
OPEN XDO_CURSOR FOR
'SELECT TO_CHAR(SYSDATE,''MM-DD-YYYY'') AS CURRENT_DATE, X.STATE FROM
schemaName.XX1 X WHERE X.ID IN (300,500,600)';
RETURN XDO_CURSOR;
END IF ;
END FUNC1;
3) Log in as System and grant execute to the BI User
GRANT EXECUTE ON schemaName.FUNC1 TO BI_User;
In your Data Set in BI Publisher - You can do the following to call the function: Make sure the type of
SQL is "Procedure Call"
DECLARE
type refcursor is REF CURSOR;
xdo_cursor refcursor;
BEGIN
:xdo_cursor := SchemaName.func1(:P1);
END;
For more info you can use the link below: https://community.oracle.com/thread/888365
It's important that we remember that ROWCOUNT reports how many rows have been fetched through the cursor. Just after
opening the cursor we haven't fetched any rows yet. If we fetch a row of data then we can see this change..
SQL> ed
Wrote file afiedt.buf
1 declare
2 v_rc sys_refcursor;
3 v_empno number;
4 v_ename varchar2(10);
5 v_mgr number;
6 v_sal number;
7 begin
8 v_rc := get_dept_emps(10); -- This returns an open cursor
9 dbms_output.put_line('Pre Fetch: Rows: '||v_rc%ROWCOUNT);
10 fetch v_rc into v_empno, v_ename, v_mgr, v_sal;
11 dbms_output.put_line('Post Fetch: Rows: '||v_rc%ROWCOUNT);
12 close v_rc;
13* end;
SQL> /
Pre Fetch: Rows: 0
Post Fetch: Rows: 1
PL/SQL procedure successfully completed.
So let's fetch all our data and display it..
SQL> ed
Wrote file afiedt.buf
1 declare
2 v_rc sys_refcursor;
3 v_empno number;
4 v_ename varchar2(10);
5 v_mgr number;
6 v_sal number;
7 begin
8 v_rc := get_dept_emps(10); -- This returns an open cursor
9 loop
10 fetch v_rc into v_empno, v_ename, v_mgr, v_sal;
11 exit when v_rc%NOTFOUND; -- Exit the loop when we've run out of data
12 dbms_output.put_line('Row: '||v_rc%ROWCOUNT||' #
'||v_empno||','||v_ename||','||v_mgr||','||v_sal);
13 end loop;
14 close v_rc;
15* end;
SQL> /
Row: 1 # 7782,CLARK,7839,2450
Row: 2 # 7839,KING,,5000
Row: 3 # 7934,MILLER,7782,1300
PL/SQL procedure successfully completed.
And what happens if we try and fetch more data after it's finished, just like we tried to do in SQL*Plus..
SQL> ed
Wrote file afiedt.buf
1 declare
2 v_rc sys_refcursor;
3 v_empno number;
4 v_ename varchar2(10);
5 v_mgr number;
6 v_sal number;
7 begin
8 v_rc := get_dept_emps(10); -- This returns an open cursor
9 loop
10 fetch v_rc into v_empno, v_ename, v_mgr, v_sal;
11 exit when v_rc%NOTFOUND; -- Exit the loop when we've run out of data
12 dbms_output.put_line('Row: '||v_rc%ROWCOUNT||' #
'||v_empno||','||v_ename||','||v_mgr||','||v_sal);
13 end loop;
14 close v_rc;
15 fetch v_rc into v_empno, v_ename, v_mgr, v_sal;
16* end;
SQL> /
Row: 1 # 7782,CLARK,7839,2450
Row: 2 # 7839,KING,,5000
Row: 3 # 7934,MILLER,7782,1300
declare
*
ERROR at line 1:
ORA-01001: invalid cursor
ORA-06512: at line 15
As expected we get an error.
So now we understand the basics of what a ref cursor is.
You can clearly see that it is just a pointer to the query and it doesn't contain any data itself, it just allows us to reference the
query so that we can fetch data as we require it.
(Ok, I know the ref cursor is referencing more than just the empno in that example, but it would still result in the same error if it
just referenced the empno)
The problem we're having is because the ref cursor isn't a table of data either in the literal database sense or in an array sense,
and it's not a set of data that can be compared with the IN clause.
So what's the point in these ref cursors? Is there a way we can use them?
Yes there is..
First let's create a type structure on the database. Remember, SQL cannot access PL/SQL table structures so the type must be a
database object..
SQL> create or replace type emptype as object(empno number,
2 ename varchar2(10),
3 mgr number,
4 sal number);
5 /
Type created.
SQL> create or replace type t_emptype as table of emptype;
2 /
Type created.
Ok, so we have a structure to hold a record and a type that is a table of that structure. So far so good. But in order to populate
that structure with data coming from the ref cursor we can't just select from it as we saw above. Instead we need to provide
some PL/SQL to actually do the fetching of data for us and populate the structure..
SQL> ed
Wrote file afiedt.buf
1 create or replace function populate_emps(deptno in number := null)
2 return t_emptype is
3 v_emptype t_emptype := t_emptype(); -- Declare a local table structure and
initialize it
4 v_cnt number := 0;
5 v_rc sys_refcursor;
6 v_empno number;
7 v_ename varchar2(10);
8 v_mgr number;
9 v_sal number;
10 begin
11 v_rc := get_dept_emps(deptno);
12 loop
13 fetch v_rc into v_empno, v_ename, v_mgr, v_sal;
14 exit when v_rc%NOTFOUND;
15 v_emptype.extend;
16 v_cnt := v_cnt + 1;
17 v_emptype(v_cnt) := emptype(v_empno, v_ename, v_mgr, v_sal);
18 end loop;
19 close v_rc;
20 return v_emptype;
21* end;
SQL> /
Function created.
The above function calls the function that opens the ref cursor, then loops through, fetching each row and populating our SQL
type structure. When all rows have been fetched, the ref cursor is closed and the SQL table structure is passed back from the
function.
So now we have something in an structure that SQL understands, we should be able to query directly from it..
SQL> select * from table(populate_emps(30));
EMPNO ENAME MGR SAL
---------- ---------- ---------- ----------
7499 ALLEN 7698 1600
7521 WARD 7698 1250
7654 MARTIN 7698 1250
7698 BLAKE 7839 2850
7844 TURNER 7698 1500
7900 JAMES 7698 950
6 rows selected.
and
SQL> select * from emp where empno in (select empno from table(populate_emps(30)));
EMPNO ENAME JOB MGR
HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ----------- ---------- ---------- --------
--
7499 ALLEN SALESMAN 7698 20-FEB-
1981 1600 300 30
7521 WARD SALESMAN 7698 22-FEB-
1981 1250 500 30
7654 MARTIN SALESMAN 7698 28-SEP-
1981 1250 1400 30
7698 BLAKE MANAGER 7839 01-MAY-
1981 2850 30
7844 TURNER SALESMAN 7698 08-SEP-
1981 1500 0 30
7900 JAMES CLERK 7698 03-DEC-
1981 950 30
6 rows selected.
SQL>
Hoorah!
We've successfully taken our ref cursor (pointer) and used it to fetch the data back that we want in a structure that SQL can
understand. Ok, the examples are pretty meaningless as they stand as we could easily have achieved the same results through a
basic select, but the method is what is important to understand here.
Summary
In summary, the one key thing to remember is..
REF CURSORS ARE NOT DATA CONTAINERS. ONCE OPENED, THEY ARE SIMPLY A POINTER TO A
QUERY THAT HAS YET TO FETCH DATA.
Other articles in the PL/SQL 101 series:
PL/SQL 101 : Cursors and SQL Projection
PL/SQL 101 : Exception Handling