Ошибка Oracle TO_DATE NOT throwing
Я просто заметил любопытное поведение оракула TO_DATE при использовании с format_mask.
В основном, я вижу, что в одном случае он игнорирует данную маску формата и анализирует ввод своей собственной маской, а в других случаях генерирует исключение.
Пример I ожидаемое поведение - ошибка брошена:
SELECT TO_DATE('18-02-2016', 'DD/MON/YYYY') FROM dual
ORA-01843: недействительный месяц
Пример II неожиданное поведение - дата проанализирована:
SELECT TO_DATE('18-feb-2016', 'DD/MM/YYYY') FROM dual
18 февраля 2016 00:00:00
Я не вижу никаких замечаний этого в документах, поэтому мне интересно, является ли это непоследовательность по дизайну или это ошибка, или, может быть, я не понимаю что-то правильное?
Edit:
Глядя на ответы, я могу согласиться, что это, скорее всего, по дизайну. Но то, что делается здесь, выглядит опасно "автоматическим" для меня.
Что делать, если формат будет интерпретироваться (догадаться оракулом) неправильно? Есть ли какая-либо документация о том, что здесь происходит, поэтому я могу быть уверен, что это безопасно?
Мой вопрос будет тогда - я могу отключить его? Является ли мой единственный вариант проверки формата самостоятельно?
Ответы
Ответ 1
См. таблицу здесь: https://docs.oracle.com/cd/B28359_01/server.111/b28286/sql_elements004.htm#g195479
Это часть правила правил преобразования строк в дату модели формата Datetime. В случае MM
, если нет совпадения, он пытается выполнить MON
и MONTH
. Аналогично, если вы укажете MON
и не найдете этого, он попытается MONTH
. Если вы укажете MONTH
и он не сможет найти это, он попытается MON
, но никогда не будет пытаться MM
на что угодно, кроме MM
.
В ответ на вопрос: Can I turn it off?
Ответ: Да.
Вы можете сделать это, указав FX
как часть вашего форматирования.
SELECT TO_DATE('18/february/2016', 'FXDD/MM/YYYY') FROM dual;
Теперь возвращается:
[Ошибка] Выполнение (4: 16): ORA-01858: нечисловой символ был где ожидалось число
Принимая во внимание следующее:
SELECT TO_DATE('18/02/2016', 'FXDD/MM/YYYY') FROM dual;
Возвращает ожидаемое:
2/18/2016
Обратите внимание, что при указании FX
вы ДОЛЖНЫ использовать соответствующие разделители, иначе это будет ошибка.
Ответ 2
Это по дизайну. Oracle пытается найти детерминированное представление даты в строке, даже если не соответствует определенной маске. Он выдает ошибку только в том случае, если она не находит детерминированной даты или какой-либо необходимый компонент даты отсутствует или не разрешен.
Ответ 3
Я думаю, что 02
может означать дату/месяц/год, но feb
будет означать только одно: a month
.
Также я перекрестно проверил то же самое в 11g
и получил тот же результат, что и в 12c
. Таким образом, имеет дизайн оракула.
Ответ 4
Если вы хотите отключить попытку Oracle быть полезной и интерпретировать вещи, которые точно не совпадают, вы можете использовать модификатор формата FX:
FX
Формат точный. Этот модификатор определяет точное соответствие для модели символьного аргумента и модели формата даты и времени функции TO_DATE:
- Пунктуация и цитируемый текст в аргументе символа должны точно соответствовать (за исключением случая) соответствующим частям модели формата.
- Символьный аргумент не может иметь дополнительных пробелов. Без FX Oracle игнорирует дополнительные пробелы.
- Числовые данные в аргументе символа должны иметь такое же количество цифр, что и соответствующий элемент в модели формата. Без FX числа в аргументе символа могут опускать начальные нули.
- Когда FX включен, вы можете отключить эту проверку для ведущих нулей, используя также модификатор FM.
Итак, ваш пример будет ошибочным:
SELECT TO_DATE('18-feb-2016', 'FXDD/MM/YYYY') FROM dual;
SQL Error: ORA-01858: a non-numeric character was found where a numeric was expected
Это также потребует, чтобы разделители соответствовали точно:
SELECT TO_DATE('18-02-2016', 'FXDD/MM/YYYY') FROM dual;
SQL Error: ORA-01861: literal does not match format string
Если вы это исправите, то это ОК:
SELECT TO_DATE('18/02/2016', 'FXDD/MM/YYYY') FROM dual;
SELECT TO_DATE('18-feb-2016', 'FXDD-MON-YYYY') FROM dual;
Он не жалуется на другой случай во втором примере. Но он будет жаловаться, если вы опустите ведущие нули;
SELECT TO_DATE('18/2/2016', 'FXDD/MM/YYYY') FROM dual;
SQL Error: ORA-01862: the numeric value does not match the length of the format item
... если вы также не включили модификатор FM:
SELECT TO_DATE('18/2/2016', 'FMFXDD/MM/YYYY') FROM dual;