Literal no coincide con la cadena de formato para to_date Oracle SQL en una columna de serie
Pregunta
Estimado SQL Gurús de desbordamiento de pila:
Medio Ambiente: Oracle
Estoy tratando de entender por qué no puedo hacer una selección to_date en una columna de tabla que contiene las cuerdas. Nota tableZ con una columna de Nombre de valor en el ejemplo siguiente contiene un montón de cuerdas, algunos de los cuales son el formato correcto, por ejemplo 6/20/2010 00:00:00.
tableZ
| Value |
| __________________ |
| 6/21/2010 00:00:00 |
| Somestring |
| Some Other strings |
| 6/21/2010 00:00:00 |
| 6/22/2010 00:00:00 |
Las siguientes obras:
SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') somedate
FROM tableX a, tableY b, tableZ c
WHERE Lower(a.name) = 'somedate'
AND a.id = b.other_id
AND b.id = c.new_id
Esto vuelve algo así (que es bueno):
| somedate |
| __________________ |
| 21.06.2010 00:00:00 |
| 21.06.2010 00:00:00 |
| 22.06.2010 00:00:00 |
Lo siguiente no funciona
SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') somedate
FROM properties$aud a, template_properties$aud b, consumable_properties$aud c
WHERE Lower(a.name) = 'somedate'
AND a.id = b.property_id
AND b.id = c.template_property_id
AND To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') IS NOT NULL
se vuelva con:
ORA-01861: literal no coincide con la cadena de formato
¿Qué me estoy perdiendo aquí? Sólo una pequeña nota:
...
AND b.id = c.template_property_id
AND To_Date(c.Value, 'DD.MM.YYYY HH24:MI:SS') IS NOT NULL
no funciona bien.
Gracias !!
Objetivo para poder hacer consultas sobre la fecha ENTRE c.value el fin de seleccionar los intervalos de fechas.
Solución
El orden en que Oracle evalúa las condiciones encontradas en la cláusula WHERE no es fijo. Es decir que puede elegir evaluar la condición que contiene TO_DATE antes de que los otros criterios, en cuyo caso la consulta fallará. Para evitar esto, se suman los ordered_predicates hacen alusión a la consulta, pero tenga en cuenta que esto puede requerir un ajuste manual adicional para mejorar el rendimiento.
SELECT /*+ ordered_predicates */
To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') somedate
FROM properties$aud a,
template_properties$aud b,
consumable_properties$aud c
WHERE Lower(a.name) = 'somedate'
AND a.id = b.property_id
AND b.id = c.template_property_id
AND To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') IS NOT NULL
Al parecer ordered_predicates
está en desuso a partir de 10 g. En ese caso, creo que su única opción es utilizar una sub-consulta de tal manera que optimizador está obligado a evaluar en primer lugar (es decir, no puede combinar las consultas). La forma más sencilla de hacer esto es poner rownum
en el estado en que de la consulta interna.
SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') somedate
FROM (SELECT value
FROM properties$aud a,
template_properties$aud b,
consumable_properties$aud c
WHERE Lower(a.name) = 'somedate'
AND a.id = b.property_id
AND b.id = c.template_property_id
AND rownum > 0)
WHERE To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') IS NOT NULL
Otros consejos
create or replace function to_date_or_null(v_str_date in varchar2
, v_str_fmt in varchar2 default null) return date as
begin
if v_str_fmt is null then
return to_date(v_str_date);
else
return to_date(v_str_date, v_str_fmt);
end if;
exception
when others then
return null;
end to_date_or_null;
/
Pruebas:
SQL> select to_date_or_null('2000-01-01', 'YYYY-MM-DD') from dual -- Valid;
TO_DATE_OR_NULL('20
-------------------
2000-01-01 00:00:00
SQL> select to_date_or_null('Not a date at all') from dual -- Not Valid;
TO_DATE_OR_NULL('NO
-------------------
SQL> select to_date_or_null('2000-01-01') from dual -- Valid matches my NLS settings;
TO_DATE_OR_NULL('20
-------------------
2000-01-01 00:00:00
SQL> select to_date_or_null('01-Jan-00') from dual -- Does not match my NLS settings;
TO_DATE_OR_NULL('01
-------------------
Otra técnica es incrustar la conversión en un caso. Por ejemplo
SELECT * FROM table
WHERE col_a = '1'
AND case when col_a = '1' then to_date(col_b,'DD/MM/YYYY') end = trunc(sysdate)
Esto se pone muy fea rápido cuando las cláusulas se complican sin embargo.
¿Quieres comprobar si c.value es un formato válido con
AND To_Date(c.Value, 'DD.MM.YYYY HH24:MI:SS') IS NOT NULL
? Esto no funcionará, tendrá que realizar la comprobación de algún otro modo. Se podría utilizar una expresión regular (supongo, no los utilizó en un tiempo). Mejor aún si su modelo de datos permitiría a discernir las filas en cuestión.