Oracle (and other databases) are under no obligation to evaluate the predicate applied to an inline view before evaluating the outer predicate. Frequently, in fact, from a performance optimization standpoint, you want the optimizer to push a selective predicate from an outer query into a view, inline view, or subquery. In this case, whether the query throws an error will depend on the query plan the optimizer chooses and which predicate it actually evaluates first.
As a quick hack, you can change the inline view to prevent predicates from being pushed. In this case, the presence of a rownum
stops the optimizer from pushing the predicate. You could also use hints like no_push_pred
to try to force the optimizer to use the plan you want
select *
from ( select t.*, rownum rn
from tbl t
where col <> 'A')
where to_Date(col,'DD/MM/YYYY') = to_date('01/01/2020','DD/MM/YYYY');
The issue with either of these quick hacks, though, is that some future version of the optimizer might have more options than you are aware of today so you may have problems in the future.
A better option is to rewrite the query such that you don't care what order the predicates are evaluated. In this case (depending on Oracle version), that's pretty easy since to_date
allows you to specify a value when there is a conversion error
select *
from tbl
where col <> 'A'
and to_Date(col default null on conversion error,'DD/MM/YYYY') =
to_date('01/01/2020','DD/MM/YYYY');
If you're on an earlier version of Oracle or to_date
is just an example of the actual problem, you can create a custom function that does the same thing.
create function safe_to_date( p_str in varchar2, p_fmt in varchar2 )
return date
is
begin
return to_date( p_str, p_fmt );
exception
when value_error
then
return null;
end safe_to_date;
select *
from tbl
where col <> 'A'
and safe_to_date(col,'DD/MM/YYYY') = to_date('01/01/2020','DD/MM/YYYY');
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…