хранимая процедура ... принимает строку, созданную системой, которая каким-то образом закодирована, и возвращает другую строку в формате ГГГГММДДччммсс, если ввод не дает действительной даты, он возвращает строку «00».
Если он действительно возвращает «00000000000000» (или , как выясняется, , «19000000000000»), то это вызовет эту ошибку:
select to_date('00000000000000', 'YYYYMMDDhh24miss') from dual;
ORA-01843: not a valid month
select to_date('19000000000000', 'YYYYMMDDhh24miss') from dual;
ORA-01843: not a valid month
Когда вы запрашиваете представление без условия, вы либо ограничиваете до 10 неопределенных строк с помощью where rownum<10
, как вы показали, либо ваш клиент только извлекает и отображает «первые» несколько строк или блоков строк (например, 50 строк по умолчанию в SQL Разработчик). Процедура (которая на самом деле является функцией, предположительно ...) вызывается только для тех нескольких строк, которые не содержат проблемных c данных.
Когда у вас есть условие, каждая строка должна быть оценивается, поэтому вы сталкиваетесь с проблемой c one.
Вы можете избежать проблемы, изменив представление, чтобы сделать что-то вроде:
TO_DATE(
case
when DataOraModifica = '00' then null
when DataOraModifica = '00000000000000' then null
when DataOraModifica = '19000000000000' then null
else DataOraModifica
end,
'YYYYMMDDhh24miss'
)
db <> fiddle
Между прочим, я обычно записываю условие как
where dataoramodifica >= trunc(sysdate) - 15;
, которое должно выполнять меньше работы и позволяло бы использовать индекс для столбца; что здесь вряд ли имеет значение, поскольку столбец представления в любом случае является вызовом функции. Использование trunc(sysdate)
будет включать все данные с этой даты начала, а не только с текущего времени в эту дату - неясно, что вы на самом деле хотите.
Глядя на проверку длины, которую вы уже выполняли, вы можете включить это как:
case when length(F_Convert2NormalDate(DataOraModifica)) != 14
or F_Convert2NormalDate(DataOraModifica) = '00'
or F_Convert2NormalDate(DataOraModifica) = '00000000000000'
or F_Convert2NormalDate(DataOraModifica) = '19000000000000'
then date '1900-01-01'
else TO_DATE(DataOraModifica, 'YYYYMMDDhh24miss')
end
Или, если вы используете последнюю версию Oracle (12.2+), вы можете позволить to_date()
обрабатывать любое состояние ошибки:
TO_DATE(DataOraModifica default '19000101000000' on conversion error,
'YYYYMMDDhh24miss')
Возможно, это скроет другие проблемы, которые вы действительно хотели бы выдать ошибку, поэтому вы знаете, что есть что-то, что вам нужно исправить, но это не похоже на это из вашего описания.
db <> fiddle
Чтобы определить значения, вызывающие проблему, вы можете сделать что-то вроде этого:
set serveroutput on
declare
str varchar2(30);
dt date;
begin
for r in (select dataoramodifica from mytable) loop
begin
str := F_Convert2NormalDate(r.DataOraModifica);
dt := case when length(str) = 14
then TO_DATE (str, 'YYYYMMDDhh24miss')
else TO_DATE('19000101000000', 'YYYYMMDDhh24miss')
end;
exception
when others then
dbms_output.put_line(r.DataOraModifica || ' -> ' || str || ' => ' || sqlerrm);
end;
end loop;
end;
/
Это попытается преобразовать каждое значение в таблице одно за другим; при обнаружении проблемы он сообщит об этом, но продолжит работу. Вы, конечно, можете добавить в отладку другие полезные данные, например значение первичного ключа строки.