2010-04-06 6 views
5

11g Oracle 2, la requête suivante donne un ORA-01790: l'expression doit avoir le même type de données que l'expression correspondante:récursive SQL donnant l'aide 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; 

L'erreur indique que le type de données des deux sous-requêtes de Les UNION ALL retournent différents types de données.

Même si je convertis en TIMESTAMP dans chacune des sous-requêtes, j'obtiens la même erreur.

Qu'est-ce qui me manque?

EDIT: Je ne suis pas à la recherche d'un remplacement par CONNECT BY.

+0

Quel est le type de 'time_interval' et pourquoi votre titre dit * récursive *? –

+0

@Peter: La vue WITH fait référence à elle-même. C'est nouveau dans 11gR2. voir http://download.oracle.com/docs/cd/E11882_01/server.112/e10881/chapter1.htm#FEATURENO08835 – PenFold

+0

Impossible de voir cela, désolé. –

Répondre

6

À mon avis, « récursif des sous-requêtes Factoring » est cassé en 11g R2 pour les requêtes avec colonne de date ou d'horodatage.

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 

utiliser un casting pour convertir le type de données:

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 

Jetant un jour en une date contribue, mais où sont les autres résultats?

Il est encore mieux ...

Essayez avec une autre date de début:

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 

compte à rebours? Pourquoi?

Mise à jour 14-Jan-2014: Pour contourner ce problème, utilisez le CTE à partir de la date de fin et la construction arrière du CTE récursive, comme ceci:

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 

Résultats:

|        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 a été réalisé avec:

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

Je ne sais pas à propos de l'incompatibilité de type, mais voici une autre méthode pour accomplir ce que je pense que vous voulez (qui fonctionne en 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

Merci Dave, mais je suis à la recherche d'une solution qui utilise la syntaxe SQL récursive plus propre. – PenFold

2

Odd - WOR ks si vous passez autour varchar s et convertir (non 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