I have a weird behavior going on here, and I’m hoping someone can explain it to me.
I have two fields in a query. One is a numeric field that is converted to a date by taking to_date('01/01/1960', 'mm/dd/yyyy') + somethingorother. Another is a text field, which includes at least one non-date value, that is converted to a date with to_date(textField, 'mm/dd/rrrr'). If I run the query, it runs fine. However, if I enclose the query in select * from ( ) where field1 > field2, it blows up with an “ORA-01861: literal does not match format string” error. If I try excluding the known non-date value in the where clause of the subquery that pulls back the text field, it doesn’t help.
I know this is almost impossible to figure out without code, but I’m wondering if anyone can explain to me why it works without the filter, but blows up when I add it. Thanks.
The general problem is that since SQL is a set-based language, Oracle is free to evaluate your predicates in any order it chooses. If you have a
VARCAHR2column that stores some date values and some non-date values, that means that Oracle is free to either evaluate the predicate that filters out all of the non-date values first or to evaluate the predicate that checks whether one of the convertedDATEvalues is greater than the other first. If it happens to evaluate theDATEinequality predicate (field1 > field2) before filtering out the non-date values, you’ll get an error.The fact that SQL is set-based is one of the major reasons that using the wrong data type is so problematic– you can’t ever be certain that a query is always going to filter out the non-convertable data before calling the conversion function. Even if you set up abstraction barriers like views that filter out the invalid data, the optimizer is free to reorder predicates so you can easily find that your queries end up breaking your abstraction barriers or that you have queries that work most of the time unless the optimizer happens to pick a different execution plan. Jonathan Gennick has a very enjoyable article Subquery Madness that talks about this specific issue.
You can write your own conversion function that ignores the exceptions and use that in your query. For example, you can create a function
and then use that function in your query
That will work because it will be valid to call
my_to_dateon any string whether or not it evaluates to a validDATEso your query no longer depends on the order in which Oracle chooses to evaluate the predicates.