Littérales ne correspond pas à la chaîne de format pour to_date Oracle SQL sur une colonne de chaîne

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

  •  29-09-2019
  •  | 
  •  

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.

Était-ce utile?

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top