ORA-01861 исключение, которое то есть, то нет


create table test_date (f1 date);
insert into test_date values(null);
commit;

-- statement 1
update test_date set f1 = TO_DATE( '06.02.2023', 'YYYY-MM-DD HH24:MI:SS' );
-- statement 2
update test_date set f1 = TO_DATE( '06.02.2024', 'YYYY-MM-DD HH24:MI:SS' );
commit;

Первый запрос обработается без исключения.
Второй запрос выбросит ошибку ORA-01861.
В таблице в поле f1 будет лежать вообще что-то загадочное.

В чем проблема?


Ответы (1 шт):

Автор решения: Igor Egorov

Чтобы ответить на этот вопрос, в чем разница между 2023 и 2024, можно написать простой скрипт.

create table test_dataformet_log (
   inp_date date
  ,str_date varchar2(64)
  ,new_date date
  ,matbe_exception number(1)
  ,errcode varchar2(64)
);

declare
   v_stdate date := to_date('01-01-1900', 'DD-MM-YYYY');
   v_newdate date;
   v_cnt number := 50000;
   v_strdate varchar2(64);
   v_errcd varchar2(32);
begin
   
   for pos in 1..v_cnt loop
     v_stdate := v_stdate + 1;
     
     declare
     begin
         v_strdate := to_char(v_stdate, 'DD.MM.YYYY');
         v_newdate := to_date(v_strdate, 'YYYY-MM-DD HH24:MI:SS');

         insert into test_dataformet_log values (v_stdate, v_strdate, v_newdate, null, null);
     exception 
        when others then
         v_errcd := SQLCODE;
    
         insert into test_dataformet_log values (v_stdate, v_strdate, null, 1, v_errcd);

     end;
   end loop;
   
end;
/

И самый беглый взгляд на результаты скажет, что оракл не проверяет соответствие строки ожидаемому формату даты, а неведомой перестановкой байт просто пытается сконвертировать то, что подали на вход.
Так первые две цифры года становятся числом, месяц остается на месте, число становится годом (7 число месяца = 7 год нашей эры), а вот последние две цифры года попадают в разряд часов.
Исключение генерируются только если часы оказываются больше 23.
То есть, если вы пытаетесь конвертировать таким способом даты с 01.01.2000 по 31.12.2023 - никаких исключений, все сконвертируется.

→ Ссылка