2012-09-26 14 views
6

Tengo una tabla con los siguientes campos:Oracle: un mes no válida

Informes (nombre de la tabla) Rep_Date (fecha) Rep_Time (fecha)

El campo Rep_Time tiene valores como '01/01/1753 07:30:00 'es decir, la parte de tiempo es relevante. He escrito la siguiente consulta:

select Reports.pid, MaxDate from Reports 
INNER JOIN (
    select pid, max(TO_DATE(TO_CHAR(REP_DATE, 'DD/MM/YYYY') 
     || TO_CHAR(REP_TIME, 'HH24:MI:SS'), 'DD/MM/YYYY HH24:MI:SS')) As MaxDate 
    from reports 
    group by pid 
) ReportMaxDate 
on Reports.PID = ReportMaxDate.PID 
AND To_Date(To_Char(MaxDate, 'DD/MM/YYYY')) = REP_DATE 
WHERE REPORTS.PID=61 

La parte tabla derivada de la consulta se ejecuta, pero cuando corro toda la consulta me sale un error: "no válido un mes". ¿Por qué es esto?

Para ayudar a depurar esto; si se me acaba la siguiente consulta:

select rep_date, rep_time from reports where pid=61 and rownum=1 

me sale:

Rep_Date = 01/04/2009 
Rep_Time = 01/01/1753 13:00:00 

ACTUALIZACIÓN 15:58 ahora soy capaz de ejecutar la siguiente consulta:

select Reports.pid, MaxDate from Reports 
INNER JOIN (
    select pid, max(TO_DATE(TO_CHAR(REP_DATE, 'DD/MM/YYYY') 
     || TO_CHAR(REP_TIME, 'HH24:MI:SS'), 'DD/MM/YYYY HH24:MI:SS')) As MaxDate 
    from reports group by pid 
) ReportMaxDate 
on Reports.PID = ReportMaxDate.PID 
AND to_date(to_char(maxdate,'MM/DD/YYYY'),'MM/DD/YYYY') = REP_DATE 
WHERE REPORTS.PID=61 

Sin embargo, necesito para agregar una declaración más a la cláusula WHERE que compara la parte de tiempo de MaxDate con rep_time: to_date(to_char(maxdate,'MM/DD/YYYY'),'MM/DD/YYYY') = REP_DATE no funciona.

Respuesta

21

1.

To_Date(To_Char(MaxDate, 'DD/MM/YYYY')) = REP_DATE 

está causando el problema. cuando usa to_date sin el formato de hora, oracle usará las sesiones actuales formato NLS para convertir, que en su caso podría no ser "DD/MM/YYYY". Mira esto ...

SQL> select sysdate from dual; 

SYSDATE 
--------- 
26-SEP-12 

Which means my session's setting is DD-Mon-YY 

SQL> select to_char(sysdate,'MM/DD/YYYY') from dual; 

TO_CHAR(SY 
---------- 
09/26/2012 


SQL> select to_date(to_char(sysdate,'MM/DD/YYYY')) from dual; 
select to_date(to_char(sysdate,'MM/DD/YYYY')) from dual 
       * 
ERROR at line 1: 
ORA-01843: not a valid month 

SQL> select to_date(to_char(sysdate,'MM/DD/YYYY'),'MM/DD/YYYY') from dual; 

TO_DATE(T 
--------- 
26-SEP-12 

2.

Más importante aún, ¿Por qué estás convirtiendo a char y luego hasta la fecha, en lugar de comparar directamente

MaxDate = REP_DATE 

Si desea ignorar el momento componente en MaxDate antes de la comparación, debe utilizar ...

trunc(MaxDate) = rep_date 

en su lugar.

== Actualización: basada en la pregunta actualizada.

Rep_Date = 01/04/2009 Rep_Time = 01/01/1753 13:00:00 

Creo que el problema es más complejo. si rep_time está destinado a ser solo el tiempo, entonces no puede almacenarlo en la base de datos como una fecha. Tendría que ser una cadena o un intervalo de fecha a hora o numéricamente como segundos (gracias a Alex, vea this). Si es posible, sugeriría usar una columna rep_date que tenga tanto la fecha como la hora y compararla directamente con la columna de fecha máxima.

Si se trata de un sistema en ejecución y no tiene control sobre repdate, puede intentarlo.

trunc(rep_date) = trunc(maxdate) and 
to_char(rep_date,'HH24:MI:SS') = to_char(maxdate,'HH24:MI:SS') 

De cualquier manera, el tiempo se almacena de forma incorrecta (como se puede deducir a partir del año 1753) y podría haber otros problemas en el futuro.

+0

En respuesta a su pregunta MaxDate es un DateTime y REP_DATE es una fecha. ¿Qué hace trunc (MaxDate) = rep_date DO? – w0051977

+0

trunc (date) eliminaría el componente de tiempo (en realidad, hace que el componente de tiempo sea cero, que es el caso con una columna de fecha como REP_DATE. No existe tal cosa como la fecha en Oracle.) –

+0

+1, gracias trabajos. ¿Podría explicarme cómo obtener el componente de tiempo de una fecha y hora antes de aceptar? to_date (to_char (maxdate, 'HH24: MI: SS'), 'HH24: MI: SS') no parece funcionar. – w0051977

2

Para conocer el formato de fecha real, inserte un registro con sysdate. por el puede encontrar el formato de fecha actual. por ejemplo

insert into emp values(7936,'Mac','clerk',7782,sysdate,1300,300,10); 

ahora, seleccione el registro insertado.

select ename,hiredate from emp where ename='Mac'; 

el resultado es

ENAME HIREDATE 
Mac  06-JAN-13 

listo, ahora el formato de fecha Actuel se encuentra.