Littérales ne correspond pas à la chaîne de format pour to_date Oracle SQL sur une colonne de chaîne
Question
Cher SQL Gourous de débordement de la pile:
Environnement: Oracle
Je suis en train de comprendre pourquoi je ne peux pas faire une sélection de to_date sur une colonne de table qui contient des chaînes. Note tableZ avec une colonne de nom Valeur dans l'exemple ci-dessous contient un tas de chaînes, dont certains sont le format correct, par exemple 20/06/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 |
Les travaux suivants
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
Cette fonction renvoie quelque chose comme (ce qui est bon):
| somedate |
| __________________ |
| 21.06.2010 00:00:00 |
| 21.06.2010 00:00:00 |
| 22.06.2010 00:00:00 |
Ce qui suit ne fonctionne pas
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
revient avec:
ORA-01861: littéral ne correspond pas à la chaîne de format
Qu'est-ce que je manque ici? Juste une note rapide:
...
AND b.id = c.template_property_id
AND To_Date(c.Value, 'DD.MM.YYYY HH24:MI:SS') IS NOT NULL
ne fonctionne pas non plus.
Merci !!
Objectif pour pouvoir faire jour entre les requêtes sur c.value afin de sélectionner des plages de dates.
La solution
L'ordre dans lequel Oracle évalue les conditions trouvées dans la clause where est pas fixé. C'est-à-dire qu'il peut choisir d'évaluer l'état contenant TO_DATE avant que les autres critères, dans ce cas, la requête échouera. Pour éviter cela, ajoutez les ordered_predicates allusion à votre requête, mais sachez que cela peut nécessiter un réglage manuel supplémentaire pour améliorer les performances.
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
Apparemment ordered_predicates
est dépréciée à partir de 10g. Dans ce cas, je pense que votre seule option est d'utiliser une sous-requête dans une telle façon que l'optimiseur est obligé d'évaluer d'abord (à savoir qu'il ne peut pas combiner les requêtes). La meilleure façon de le faire est de mettre rownum
dans la déclaration où la requête interne.
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
Autres conseils
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
-------------------
Une autre technique est la conversion en intégrer un cas. Par exemple
SELECT * FROM table
WHERE col_a = '1'
AND case when col_a = '1' then to_date(col_b,'DD/MM/YYYY') end = trunc(sysdate)
Cela devient vraiment rapide laid quand les clauses sont compliquées bien.
Voulez-vous vérifier si c.value est un format valide avec
AND To_Date(c.Value, 'DD.MM.YYYY HH24:MI:SS') IS NOT NULL
? Ce travail de coutume, vous devrez effectuer le contrôle d'une autre manière. Vous pouvez utiliser une expression régulière (je suppose, ne les a utilisés dans un certain temps). Mieux encore, si votre modèle de données vous permettra de discerner les lignes en question.