Литерал не соответствует форматной строке для Oracle SQL to_date в столбце строки - PullRequest
4 голосов
/ 23 июня 2010

Уважаемые гуру SQL из переполнения стека:

Среда: Oracle

Я пытаюсь понять, почему я не могу сделать выбор to_date для столбца таблицыкоторый содержит строки.Обратите внимание, что таблица tableZ со столбцом имени Value в приведенном ниже примере содержит набор строк, некоторые из которых имеют правильный формат, например 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 |

Следующие работы

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

Это возвращает что-то вроде (что хорошо):

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

Следующее не работает

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

Возвращается с:

ORA-01861: литерал не соответствует строке формата

Что мне здесь не хватает?Просто краткое замечание:

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

тоже не работает.

Спасибо !!

Цель , чтобы иметь возможность делать дату между запросамина c.value для выбора диапазонов дат.

Ответы [ 4 ]

9 голосов
/ 24 июня 2010

Порядок, в котором Oracle оценивает условия, найденные в предложении where, не является фиксированным. То есть он может выбрать оценку условия, содержащего TO_DATE, перед другими критериями, и в этом случае запрос не будет выполнен. Чтобы предотвратить это, добавьте подсказку order_predicates в свой запрос, но имейте в виду, что для повышения производительности может потребоваться дополнительная ручная настройка.

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

Очевидно, ordered_predicates устарела, начиная с 10g. В этом случае, я думаю, что ваш единственный вариант - использовать подзапрос таким образом, чтобы оптимизатор был вынужден сначала его оценить (то есть он не может объединять запросы). Самый простой способ сделать это - поместить rownum в оператор where внутреннего запроса.

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
1 голос
/ 24 июня 2010

Еще одна техника - встраивание конверсии в СЛУЧАЙ. Например

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

Это становится действительно ужасно быстрым, когда пункты сложны.

1 голос
/ 24 июня 2010
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;
/

Тестирование:

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
-------------------
0 голосов
/ 24 июня 2010

Хотите проверить, является ли c.value допустимым форматом с

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

? Это не сработает, вам нужно будет выполнить проверку другим способом. Вы могли бы использовать регулярное выражение (я думаю, не использовал их в течение некоторого времени). Еще лучше, если ваша модель данных позволит вам различать соответствующие строки.

...