Letterale non corrisponde stringa di formato per Oracle SQL to_date su una colonna di stringa
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.
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.