Литерал не соответствует строке формата для Oracle SQL to_date в строковом столбце

Уважаемые гуру SQL из Stack Overflow:

Среда: 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 для выбора диапазонов дат.


person Rio    schedule 23.06.2010    source источник


Ответы (4)


Порядок, в котором 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
person Allan    schedule 23.06.2010
comment
Хорошая идея, но мне не удалось заставить ее работать при первоначальном тестировании? - person Rio; 24.06.2010
comment
@ Рио, если тебе нужна дополнительная помощь, сказать, что у меня не получилось, недостаточно. - person Jeffrey Kemp; 24.06.2010
comment
Его комментарий был ответом только на раздел order_predicate. Остальное было добавлено, когда я исследовал, почему это не работает ... - person Allan; 24.06.2010
comment
Спасибо, Аллан. Этот ответ ценен и, надеюсь, просветит и других! - person Rio; 24.06.2010
comment
Насколько я понимаю, оптимизатор Oracle иногда помещает предикаты во встроенное представление, что приводит к срабатыванию to_date и to_number недопустимых значений, даже если встроенное представление должно их отфильтровать. Это прискорбно в случаях, подобных этому примеру. См. asktom.oracle.com/ pls / apex / и dbdebunk.com/page/page/1351381.htm - person Shannon Severance; 24.06.2010
comment
@ Шеннон Северанс, это правильно. Однако вы можете запретить oracle продвигать предикат во встроенное представление, добавив в это представление значение, которое будет изменено при изменении предиката. Это цель включения rownum во внутренний запрос. - person Allan; 24.06.2010
comment
@Allan: Спасибо, что объяснили это. - person Shannon Severance; 25.06.2010

Другой метод - встроить преобразование в CASE. Например

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

Это становится ДЕЙСТВИТЕЛЬНО уродливым быстро, когда предложения сложные.

person Gary Myers    schedule 24.06.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
-------------------
person Shannon Severance    schedule 23.06.2010

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

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

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

person bert    schedule 23.06.2010
comment
Нет, моя цель, как указано выше, - делать запросы МЕЖДУ, чтобы я мог выбирать диапазоны дат. IS NOT NULL - это просто простой способ проверить, работает ли запрос вообще, и ошибка оракула говорит об обратном. - person Rio; 24.06.2010