2010-04-06 10 views
5

Verwenden von Oracle 11g Release 2, die folgende Abfrage gibt einen ORA-01790:rekursive SQL geben 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; 

Der Fehler lässt vermuten, dass der Datentyp der beiden Unterabfragen von: Ausdruck denselben Datentyp wie entsprechende Ausdruck haben muss Die UNION ALL gibt verschiedene Datentypen zurück.

Auch wenn ich in jeder der Unterabfragen auf TIMESTAMP umsetze, bekomme ich den gleichen Fehler.

Was fehlt mir?

EDIT: Ich bin nicht auf der Suche nach einem CONNECT BY Ersatz.

+0

Was die Art der 'time_interval' ist und warum Sie Ihren Titel sagen * rekursive *? –

+0

@Peter: Die WITH-View verweist auf sich selbst. Dies ist neu in 11gR2. siehe http://download.oracle.com/docs/cd/E11882_01/server.112/e10881/chapter1.htm#FEATURENO08835 – PenFold

+0

Leider konnte ich das nicht sehen. –

Antwort

6

Meiner Meinung nach, „rekursiven Unterabfrage Factoring“ ist gebrochen in 11g R2 für Abfragen mit Datum oder Zeitstempel Spalte.

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 

Verwendung ein gegossenes den Datentyp zu konvertieren:

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 ein Datum in ein Datum hilft, aber wo sind die anderen Ergebnisse?

Es wird noch besser ...

es mit einem anderen Startdatum Versuchen:

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 

rückwärts zählt? Warum?

Aktualisieren 14-Jan-2014: Als Abhilfe können Starten des CTE mit dem Enddatum verwenden und die rekursive CTE Gebäude nach hinten, wie folgt aus:

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 

Ergebnisse:

|        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 durchgeführt mit:

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

ich keine Ahnung von dem Typenkonflikt habe, aber hier eine alternative Methode zu erreichen, was ich glaube, Sie wollen (die in 10gr2 funktionieren):

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

Danke Dave, aber ich suche nach einer Lösung, die die cleaner rekursive SQL-Syntax verwendet. – PenFold

2

Odd - wor ks, wenn Sie um varchar s passieren und konvertieren (nicht 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