2010-04-06 19 views
5

Uso de Oracle liberación 11g 2, la siguiente consulta da una ORA-01790: la expresión debe tener el mismo tipo de datos como correspondiente expresión:SQL recursivo dando 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; 

sugiere El error que el tipo de datos de ambos subconsultas de el UNION ALL está devolviendo diferentes tipos de datos.

Incluso si lanzo TIMESTAMP en cada una de las subconsultas, aparece el mismo error.

¿Qué me estoy perdiendo?

EDITAR: No estoy buscando un reemplazo de CONNECT BY.

+0

¿Cuál es el tipo de 'time_interval' y por qué el título dice recursiva * *? –

+0

@ Peter: la vista WITH se hace referencia a sí misma. Esto es nuevo en 11gR2. ver http://download.oracle.com/docs/cd/E11882_01/server.112/e10881/chapter1.htm#FEATURENO08835 – PenFold

+0

Error al ver eso, lo siento. –

Respuesta

6

En mi opinión, "recursiva Subconsulta Factoring" es roto en 11g R2 para consultas con fecha o columna de marca de tiempo.

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 

uso un molde para convertir el tipo de datos:

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 una fecha en una fecha está ayudando, pero ¿dónde están los otros resultados?

Se pone aún mejor ...

intentarlo con otra fecha de inicio:

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 

contando hacia atrás? ¿Por qué?

Actualización 14-Ene-2014: Como solución, utilice el CTE a partir de la fecha de finalización y la construcción de la CTE recursiva hacia atrás, de esta manera:

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 

Resultados:

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

realizó el ensayo con:

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

no tengo ni idea acerca de la coincidencia de tipos, pero aquí es un método alternativo para lograr lo que creo que quieres (que trabaja 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

Gracias Dave, pero estoy buscando una solución que use la sintaxis SQL sql recursiva. – PenFold

2

Odd - WOR ks Si pasa alrededor varchar s y convertir (no fundido):

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