Skip to Main Content
  • Questions
  • Recursive subquery factoring for a table function

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, KISHORE.

Asked: August 11, 2016 - 9:32 pm UTC

Last updated: August 14, 2016 - 5:39 am UTC

Version: Oracle 11g R2

Viewed 1000+ times

You Asked

Hello Sir,

I have this table function call :

select * FROM TABLE ( MOD_GENERATOR.PKG_GENERATOR_XREF.refcur_to_table_func (
MOD_GENERATOR.F_GENERATOR_XREF (trunc(sysdate)) ))

Now I have to call this 24 times every time I run this by incrementing the hour like below :

select * FROM TABLE ( MOD_GENERATOR.PKG_GENERATOR_XREF.refcur_to_table_func (
MOD_GENERATOR.F_GENERATOR_XREF (trunc(sysdate) + 1/24 ) ))

until 23/24 ...

This table function is already used in a WITH clause as part of a huge WITH caluse cluster (this is just extraneous information)

My question is :

Can I use a recursive CTE to call the above table function to pass a 'parameter' (sort of) to increment the hour 23 times ?

I did attempt it as below :

with data(r)
as
(select 1 r from dual
union all
select r+1 from data where r < 24
)
select * from (
select * FROM TABLE ( MOD_GENERATOR.PKG_GENERATOR_XREF.refcur_to_table_func (
MOD_GENERATOR.F_GENERATOR_XREF (trunc(sysdate)+ r+1/24) )
)) from data

but the value of 'r' is not recognized inside the table function.

Any advise is appreciated

Thanks

and Connor said...

Have you tried standard rownum with connect by ? eg

select * 
FROM TABLE( MOD_GENERATOR.PKG_GENERATOR_XREF.refcur_to_table_func (
              MOD_GENERATOR.F_GENERATOR_XREF (trunc(sysdate)+level+1/24) )))
from dual
connect by level <= 24


Rating

  (3 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Minor fix suggestion to original answer

Koen Lostrie, August 12, 2016 - 12:14 pm UTC

Hello Kishore,Connor,
Could it be that there is an error in the argument of MOD_GENERATOR.F_GENERATOR_XREF
To have the date argument incremented by hour the formula should be
trunc(sysdate)+level/24

The code in the question/answer will increment days not hours.
Example:
Original code:
SELECT mylevel,rundate FROM
(
  SELECT level as mylevel, TO_CHAR(TRUNC(SYSDATE) + level + 1/24,'DD-MON-YYYY HH24:MI') AS rundate FROM dual CONNECT BY level <= 24
)
WHERE mylevel NOT BETWEEN 4 AND 20;

Original result:
1 13-AUG-2016 01:00
2 14-AUG-2016 01:00
3 15-AUG-2016 01:00
21 02-SEP-2016 01:00
22 03-SEP-2016 01:00
23 04-SEP-2016 01:00
24 05-SEP-2016 01:00


Fixed code:
SELECT mylevel,rundate FROM
(
  SELECT level as mylevel, TO_CHAR(TRUNC(SYSDATE) + level/24,'DD-MON-YYYY HH24:MI') AS rundate FROM dual CONNECT BY level <= 24
)
WHERE mylevel NOT BETWEEN 4 AND 20;

Result:
1 12-AUG-2016 01:00
2 12-AUG-2016 02:00
3 12-AUG-2016 03:00
21 12-AUG-2016 21:00
22 12-AUG-2016 22:00
23 12-AUG-2016 23:00
24 13-AUG-2016 00:00


Connor McDonald
August 14, 2016 - 5:39 am UTC

Yes, nice catch.

Level with connect by works !!

KISHORE Tekali, August 12, 2016 - 1:04 pm UTC

Thank you Sir :
the below sql works for me :

select *
FROM TABLE( MOD_GENERATOR.PKG_GENERATOR_XREF.refcur_to_table_func (
MOD_GENERATOR.F_GENERATOR_XREF (trunc(sysdate)+level+1/24) ))
connect by level <= 24;

FROM DUAL was not needed ...

Level with connect by works !!

KISHORE Tekali, August 12, 2016 - 1:54 pm UTC

Hello Sir,
I observed that the performance by using CONNECT BY LEVEL is quite bad.
works 'fast' for levels upto 2 - anything higher takes a 'long' time - meaning keeps running for 20 minutes or so (and had to kill the session)
whereas a simple UNION ALL of 24 such SQL statements works remarkably fast (except that it clutters the code )
so, I am going with UNION ALL for now until I can find a better performing way to acjieve the same results
Thanks