Letterale non corrisponde stringa di formato per Oracle SQL to_date su una colonna di stringa

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

  •  29-09-2019
  •  | 
  •  

Domanda

Caro SQL Guru da Stack Overflow:

Ambiente: Oracle

Sto cercando di capire il motivo per cui non posso fare una selezione to_date su una colonna della tabella che contiene le stringhe. Nota tableZ con una colonna di Nome valore nell'esempio che segue contiene una serie di stringhe, alcuni dei quali sono nel formato corretto, ad esempio 2010/06/20 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 |

I seguenti lavori

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

Questo restituisce qualcosa di simile (che è buono):

| somedate            |
| __________________  |
| 21.06.2010 00:00:00 |
| 21.06.2010 00:00:00 |
| 22.06.2010 00:00:00 |

Quanto segue non funziona

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

torna con:

ORA-01861: letterale non corrisponde stringa di formato

Che cosa mi manca qui? Solo una breve nota:

 ...
AND b.id = c.template_property_id 
AND To_Date(c.Value, 'DD.MM.YYYY HH24:MI:SS') IS NOT NULL

non funziona neanche.

Grazie !!

Obiettivo per essere in grado di fare data tra le query su c.value al fine di selezionare intervalli di date.

È stato utile?

Soluzione

L'ordine che Oracle valuta le condizioni trovate nella clausola in cui non è fisso. Vale a dire che si può scegliere di valutare la condizione contenente TO_DATE prima che gli altri criteri, nel qual caso la query avrà esito negativo. Per evitare che, aggiungono i ordered_predicates suggerimento per la tua ricerca, ma essere consapevoli che questo può richiedere la sintonizzazione manuale aggiuntivo per migliorare le prestazioni.

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

A quanto pare ordered_predicates è deprecato a partire da 10 g. In questo caso, credo che l'unica opzione è quella di utilizzare un sub-query in modo tale che un ottimizzatore è costretto a valutarla prima (vale a dire che non è possibile combinare le query). Il modo più semplice per farlo è quello di mettere rownum nella dichiarazione in cui la query 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

Altri suggerimenti

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

Test:

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

Un'altra tecnica è incorporare la conversione in un caso. Ad esempio

SELECT * FROM table
WHERE col_a = '1'
AND case when col_a = '1' then to_date(col_b,'DD/MM/YYYY') end = trunc(sysdate)

Questo diventa veramente brutto veloce quando le clausole sono complicate però.

Vuoi verificare se c.value è un formato valido con

AND To_Date(c.Value, 'DD.MM.YYYY HH24:MI:SS') IS NOT NULL

? Questo non funzionerà, sarà necessario eseguire il controllo in qualche altro modo. Si potrebbe utilizzare un'espressione regolare (credo, non li ha usati in un po '). Meglio ancora se il modello di dati permetterebbe di discernere le righe in questione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top