Литеральная строка не соответствует строке формата для Oracle SQL TO_DATE в строковом столбце
Вопрос
Уважаемый SQL Gurus из переполнения стека:
Окружающая среда: Оракул
Я пытаюсь понять, почему я не могу сделать выбор TO_DATE на столбце таблицы, который содержит строки. Примечание Tablez с столбцом значения имени в приведенном ниже примере содержит кучу строк, некоторые из которых являются правильным форматом, например, с 20.06.2010 00:00:00.
таблица
| 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: Literal не соответствует строке формата формата
Что мне здесь не хватает? Просто быстрое примечание:
...
AND b.id = c.template_property_id
AND To_Date(c.Value, 'DD.MM.YYYY HH24:MI:SS') IS NOT NULL
тоже не работает.
Спасибо!!
Цель Чтобы иметь возможность выполнять дату между запросами на C.value, чтобы выбрать диапазоны дат.
Решение
Порядок, который Oracle оценивает условия, обнаруженные в пункте «Где не исправлен». То есть он может оценить условие, содержащее to_date перед другими критериями, и в этом случае запрос потерпит неудачу. Чтобы предотвратить это, добавьте намек на заказ на ваш запрос, но имейте в виду, что это может потребовать дополнительной ручной настройки для повышения производительности.
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
В заявлении о внутреннем запросе.
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
Другие советы
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
-------------------
Другая техника - это преобразование в случай. Например
SELECT * FROM table
WHERE col_a = '1'
AND case when col_a = '1' then to_date(col_b,'DD/MM/YYYY') end = trunc(sysdate)
Это становится очень уродливым быстро, когда положения сложны.
Вы хотите проверить, является ли C.value действительным форматом с
AND To_Date(c.Value, 'DD.MM.YYYY HH24:MI:SS') IS NOT NULL
? Это не сработает, вам нужно будет выполнить чек другим способом. Вы можете использовать регулярное выражение (я думаю, не использовал их давно). Еще лучше, если ваша модель данных позволит вам различить рассматриваемые строки.