I found this after upgrading from Oracle 11g Release 1 to Release 2.
The best I can summarize it right now is that a LEFT OUTER JOIN against a query with a constant “fake” column and a WHERE clause generates different results in the two Oracle RELEASES. In Release 2, the “fake” column shows up in the unmatched rows:
TEST1 TEST2
===== =====
A B A B
- --- - ---
1 bar 1 hello
2 baz
> SELECT * FROM test1 LEFT OUTER JOIN test2 ON test1.a = test2.a;
A B A_1 B_1
- --- --- -----
1 bar 1 hello
2 baz
So far, so good. all of the above works the same on Rel. 1 and 2. Now, add a ‘fake’ constant column X, and things work as expected:
> SELECT *
FROM test1
LEFT OUTER JOIN (SELECT test2.*, 'X' AS X
FROM test2) test3
ON test1.a = test3.a;
A B A_1 B_1 X
- --- --- ----- -
1 bar 1 hello X
2 baz
Now, add a WHERE clause on the first table and get different results:
> SELECT *
FROM test1
LEFT OUTER JOIN (SELECT test2.*, 'X' AS X
FROM test2) test3
ON test1.a = test3.a
WHERE test1.b LIKE 'ba%';
Release 11.1.0.7.0 Release 11.2.0.2.0
================== ==================
A B A_1 B_1 X A B A_1 B_1 X
- --- --- ----- - - --- --- ----- -
1 bar 1 hello X 1 bar 1 hello X
2 baz 2 baz X <--- WHAT'S THIS?!
Further puzzlement: if the WHERE condition is numeric (e.g., WHERE test1.a < 5, the results are the same!
UPDATE (to clarify my actual question):
What I am doing wrong? Is my final query somehow invoking an undefined behavior making it OK for Oracle to change what’s returned from one release to the next? If not, is this an Oracle bug?
So I am going to answer my own question, namely: “Am I doing something wrong or is this an Oracle bug?” with This is an Oracle bug.
I leave it up to you to navigate the insanity known as support.oracle.com, but, as pointed out by @AdamHawkes, this bug is probably addressed in a recent Oracle patch set. A couple of bugs in the release notes to 11.2.0.3 seem similar to my problem, though not exactly the same.
I’ll try to come back here and update the answer when I get the latest patches applied (I am in an environment where I am not in control of this).