Literal no coincide con la cadena de formato para to_date Oracle SQL en una columna de serie

StackOverflow https://stackoverflow.com/questions/3105003

  •  29-09-2019
  •  | 
  •  

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.

¿Fue útil?

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top