Recursive SQL giving ORA-01790

前端 未结 3 1425
自闭症患者
自闭症患者 2021-02-10 04:46

Using Oracle 11g release 2, the following query gives an ORA-01790: expression must have same datatype as corresponding expression:

with intervals(time_interval)         


        
相关标签:
3条回答
  • 2021-02-10 05:25

    In my opinion, "Recursive Subquery Factoring" is broken in 11g R2 for queries with date or timestamp column.

    with test(X) as
    (
      select to_date('2010-01-01','YYYY-MM-DD') from dual
      union all (
        select (X + 1) from test where X <= to_date('2010-01-10','YYYY-MM-DD') 
      )
    )
    select * from test;
    
    ORA-01790
    

    use a cast to convert the datatype:

    with test(X) as
    (
      select cast(to_date('2010-01-01','YYYY-MM-DD') as date) from dual
      union all (
        select (X + 1) from test where X <= to_date('2010-01-10','YYYY-MM-DD') 
      )
    )
    select * from test;
    
    X
    -------------------
    2010-01-01 00:00:00
    
    1 row selected
    

    Casting a date into a date is helping, but where are the other results?

    It gets even better...

    Try it with another start date:

    with test(X) as
    (
      select cast(to_date('2007-01-01','YYYY-MM-DD') as DATE) from dual
      union all (
        select (X + 1) from test where X <= to_date('2011-01-11','YYYY-MM-DD') 
      )
    )
    select * from test 
    where rownum < 10; -- important!
    
    X
    -------------------
    2007-01-01 00:00:00
    2006-12-31 00:00:00
    2006-12-30 00:00:00
    2006-12-29 00:00:00
    2006-12-28 00:00:00
    2006-12-27 00:00:00
    2006-12-26 00:00:00
    2006-12-25 00:00:00
    2006-12-24 00:00:00
    
    9 rows selected
    

    Counting backwards? Why?

    Update 14-Jan-2014: As a workaround, use the CTE starting with the end date and building the recursive CTE backwards, like this:

    with test(X) as
    (
      select cast(to_date('2011-01-20','YYYY-MM-DD') as DATE) as x from dual
      union all (
        select cast(X - 1 AS DATE) from test 
        where X > to_date('2011-01-01','YYYY-MM-DD') 
      )
    )
    select * from test 
    

    Results:

    |                              X |
    |--------------------------------|
    | January, 20 2011 00:00:00+0000 |
    | January, 19 2011 00:00:00+0000 |
    | January, 18 2011 00:00:00+0000 |
    | January, 17 2011 00:00:00+0000 |
    | January, 16 2011 00:00:00+0000 |
    | January, 15 2011 00:00:00+0000 |
    | January, 14 2011 00:00:00+0000 |
    | January, 13 2011 00:00:00+0000 |
    | January, 12 2011 00:00:00+0000 |
    | January, 11 2011 00:00:00+0000 |
    | January, 10 2011 00:00:00+0000 |
    | January, 09 2011 00:00:00+0000 |
    | January, 08 2011 00:00:00+0000 |
    | January, 07 2011 00:00:00+0000 |
    | January, 06 2011 00:00:00+0000 |
    | January, 05 2011 00:00:00+0000 |
    | January, 04 2011 00:00:00+0000 |
    | January, 03 2011 00:00:00+0000 |
    | January, 02 2011 00:00:00+0000 |
    | January, 01 2011 00:00:00+0000 |
    

    Test conducted with:

    Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
    
    0 讨论(0)
  • 2021-02-10 05:31

    Odd - works if you pass around varchars and convert (not cast):

    WITH intervals(time_interval) AS
      (SELECT to_char(TRUNC(systimestamp))
      FROM dual
      UNION ALL
      SELECT to_char(to_timestamp(time_interval) + numtodsinterval(10, 'Minute'))
      FROM intervals
      WHERE to_timestamp(time_interval) < systimestamp
      )
    SELECT to_timestamp(time_interval) time_interval
    FROM intervals
    
    0 讨论(0)
  • 2021-02-10 05:31

    I have no idea about the type mismatch, but here is an alternative method to accomplish what I think you want (which works in 10gr2):

    select base_time + numtodsinterval( 10*(level-1), 'Minute')
    from (select trunc(systimestamp) base_time from dual)
    connect by base_time + numtodsinterval( 10*(level-1), 'Minute') < systimestamp
    
    0 讨论(0)
提交回复
热议问题