2010-04-06 58 views
5

使用Oracle 11g第2版,以下查詢給出了一個ORA-01790:表達式必須具有相同的數據類型相應的表達:遞歸SQL給予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替換。

+0

什麼time_interval'的'類型以及爲什麼您的標題說*遞歸*? – 2010-04-06 17:15:02

+0

@Peter:WITH視圖引用自身。這在11gR2中是新的。 請參閱http://download.oracle.com/docs/cd/E11882_01/server.112/e10881/chapter1.htm#FEATURENO08835 – PenFold 2010-04-06 17:17:50

+0

無法看到,抱歉。 – 2010-04-06 17:25:41

回答

6

在我看來,「遞歸子查詢分解」是對於具有日期或時間戳列的查詢,在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 

倒數?爲什麼?

更新14-JAN-2014:作爲一種變通方法,使用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 
0

我不知道類型不匹配的想法,但這裏還是要完成我想你想(在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

感謝戴夫,但我正在尋找一種使用更清晰的遞歸sql語法的解決方案。 – PenFold 2010-04-06 20:01:12

2

奇數 - wor如果你繞過varchar S和轉換(不投)KS:

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