Home > Mobile >  Function retuning Sys Refcursor
Function retuning Sys Refcursor

Time:03-23

enter image description hereHow to call a function returning sys refcursor in select statement. I have created a function like this and I want to call in the select statement returning both values coming from function. So I used in the query like this, but it is returning cursor in place of column values.

Function HCLT_GET_TASK_DATES(i_ownerid IN NUMBER, i_itemid IN NUMBER)
  RETURN SYS_REFCURSOR IS
  o_DATACUR SYS_REFCURSOR;
begin
  open o_DATACUR for
    select nvl(TO_CHAR(min(pref_start), 'DD-MON-YYYY'), '') AS MIN_DATE,
           nvl(TO_CHAR(max(pref_finish), 'DD-MON-YYYY'), '') AS MAX_DATE
      from autoplanallocation
     WHERE project_id = i_ownerid
       AND task_id = i_itemid;
  RETURN o_DATACUR;
END;
/

SELECT HCLT_GET_TASK_DATES(267157, 15334208),
       tv.taskid,
       tv.wbs_code AS wbscode,
       tv.taskcode,
       tv.act_name,
       ltrim(regexp_replace(tv.stageactorlovs, '[^#]*#(\d ?),', ',\1'), ',') as stageactorlovs,
       tv.createdat,
       tv.pushedtoTaskModule,
       tv.OVERALLSTATUS AS overallstatus1,
       tv.ACTIVITY_CODE_ID,
       tv.wbs_code,
       TO_CHAR(tv.pref_st, 'DD-MON-YYYY') AS pref_st,
       TO_CHAR(tv.pref_fn, 'DD-MON-YYYY') AS pref_fn,
       tv.ACTL_EFFORT,
       tv.rollup_effort,
       tv.overAllStatus,
       tv.FIELD5,
       tv.FIELD4,
       tv.activity_code_id
  FROM task_view tv, autoplanallocation al
 WHERE al.project_id = tv.ownerid( )
   and al.task_id = tv.taskid( )
   and tv.ownertype = 'Prj'
   AND tv.ownerid = 267157
   AND (tv.overAllStatus = 'All' OR 'All' = 'All')
   AND (TaskId IN
       ((SELECT xyz
            FROM (SELECT ToItemID xyz
                    FROM ItemTraceability it
                   WHERE it.FromOwnerType = 'Prj'
                     AND it.FromOwnerID = 267157
                     AND it.FromItemType = it.FromItemType
                     AND it.FromChildItemType = 'USTRY'
                     AND it.FromItemID = 15334208
                     AND it.ToOwnerType = 'Prj'
                     AND it.ToOwnerID = 267157
                     AND it.ToItemType = it.ToItemType
                     AND it.ToChildItemType = 'Tsk'
                  UNION ALL
                  SELECT FromItemID
                    FROM ItemTraceability it
                   WHERE it.ToOwnerType = 'Prj'
                     AND it.ToOwnerID = 267157
                     AND it.ToItemType = it.ToItemType
                     AND it.ToChildItemType = 'USTRY'
                     AND it.ToItemID = 15334208
                     AND it.FromOwnerType = 'Prj'
                     AND it.FromOwnerID = 267157
                     AND it.FromItemType = it.FromItemType
                     AND it.FromChildItemType = 'Tsk'))))
 ORDER BY UPPER(wbs_code) ASC;

CodePudding user response:

I do not think there is a native way of parsing nested cursors using SQL or PL/SQL code.


In Java with an Oracle JDBC database driver, you can:


If you want an SQL solution then do not return a cursor and return a nested table collection data type instead.

Or, for a single row with multiple columns, return an object type:

CREATE TYPE date_range_obj AS OBJECT(
  start_date DATE,
  end_date   DATE
)
/

CREATE FUNCTION HCLT_GET_TASK_DATES(
  i_ownerid IN autoplanallocation.project_id%TYPE,
  i_itemid  IN autoplanallocation.task_id%TYPE
)
RETURN date_range_obj
IS
  v_range date_range_obj;
begin
  SELECT date_range_obj(MIN(pref_start), MAX(pref_finish))
  INTO   v_range
  FROM   autoplanallocation
  WHERE  project_id = i_ownerid
  AND    task_id = i_itemid;

  RETURN v_range;
END;
/

Then, for example:

SELECT HCLT_GET_TASK_DATES(1,2).start_date,
       HCLT_GET_TASK_DATES(1,2).end_date
FROM   DUAL;

db<>fiddle here

CodePudding user response:

If you are able to change this design, then it would be better to do in plain join and aggregation (or possibly with left join lateral in case of low cardinality input).

But there's a way to achieve the desired result with plain SQL in 11g and above using the ability of dbms_xmlgen package to process arbitrary cursor. Below is the code:

create table t_lkp (id,dt)
as
select
  trunc(level/4   1)
  , date '2022-01-01'   level
from dual
connect by level < 11
create or replace function f_lkp (
  p_id in int
)
return sys_refcursor
as
  o_res sys_refcursor;
begin
  open o_res for
    select
      min(dt) as dtfrom
      , max(dt) as dtto
    from t_lkp
    where id = p_id;
  
  return o_res;
end;
/
with a as (
  select
    level as i,
    dbms_xmlgen.getxmltype(
      /*ctx doesn't accept sys_refcursor, so we had to create a context*/
      ctx => DBMS_XMLGEN.NEWCONTEXT(f_lkp(level))
    ) as val
  from dual
  connect by level < 6
)
select
  i
  , xmlquery(
    '/ROWSET/ROW/DTFROM/text()'
    passing a.val returning content null on empty
  ) as dtfrom
  , xmlquery(
    '/ROWSET/ROW/DTTO/text()'
    passing a.val returning content null on empty
  ) as dtto
from a
 I | DTFROM              | DTTO               
-: | :------------------ | :------------------
 1 | 2022-01-02 00:00:00 | 2022-01-04 00:00:00
 2 | 2022-01-05 00:00:00 | 2022-01-08 00:00:00
 3 | 2022-01-09 00:00:00 | 2022-01-11 00:00:00
 4 | null                | null               
 5 | null                | null               

db<>fiddle here

Please note, that it will open too many cursors in case of large input dataset and parallel processing, which will dramatically consume resourses. So it would be much better to use plain join.

  • Related