【问题标题】:Recursive SQL giving ORA-01790递归 SQL 给出 ORA-01790
【发布时间】:2011-02-04 21:52:18
【问题描述】:

使用 Oracle 11g 第 2 版,以下查询给出 ORA-01790:表达式必须与相应的表达式具有相同的数据类型:

with intervals(time_interval) AS
 (select trunc(systimestamp)
    from dual
  union all
  select (time_interval + numtodsinterval(10, 'Minute'))
    from intervals
   where time_interval < systimestamp)
select time_interval from intervals;

错误提示 UNION ALL 的两个子查询的数据类型返回不同的数据类型。

即使我在每个子查询中强制转换为 TIMESTAMP,也会得到相同的错误。

我错过了什么?

编辑:我不是在寻找 CONNECT BY 替代品。

【问题讨论】:

标签: sql oracle oracle11g ora-01790


【解决方案1】:

在我看来,“递归子查询分解”在 11g R2 中被破坏,用于带有日期或时间戳列的查询。

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

使用强制转换来转换数据类型:

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

将日期转换为日期会有所帮助,但其他结果在哪里?

它变得更好......

换一个开始日期试试:

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

倒数?为什么?

2014 年 1 月 14 日更新:作为一种解决方法,使用从结束日期开始的 CTE 并向后构建递归 CTE,如下所示:

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 

结果:

|                              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 |

测试通过:

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production

【讨论】:

    【解决方案2】:

    奇数 - 如果您绕过 varchars 并转换(不强制转换),则有效:

    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
    

    【讨论】:

      【解决方案3】:

      我不知道类型不匹配,但这里有另一种方法来完成我认为你想要的(在 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
      

      【讨论】:

      • 感谢 Dave,但我正在寻找一种使用更简洁的递归 sql 语法的解决方案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-17
      • 1970-01-01
      相关资源
      最近更新 更多