Here’s a suggestion to help you avoid wasting time. If you ever include the rowid in a query – not that that should happen very commonly – make sure you give it an alias, especially if you’re using ANSI SQL. If you don’t, you may find yourself struggling to work out why you’re getting an irrational error message. Here’s an example that appeared recently on the OTN forum, with the output cut-n-pasted from a system running 220.127.116.11:
select '1' from dual a left join ( select c.dummy, b.rowid from dual b join dual c on b.dummy = c.dummy ) d on a.dummy = d.dummy ; select * ERROR at line 1: ORA-01445: cannot select ROWID from, or sample, a join view without a key-preserved table
The error doesn’t really seem to fit the query, does it?
If you want to bypass the problem all you have to do is give b.rowid (line 7) an alias like rid.
As far as I can tell, the problem arises from a defect in the code that Oracle uses to transform the query before optimising it. Given the nature of the transformation it’s possible that you’re only going to see the problem manifest like this if the SQL uses ANSI forms; in this particular case changing from the ANSI left outer join syntax to Oracle’s standard (+) syntax also bypasses the problem. To narrow down the cause, I simply enabled event 10053 (the optimizer trace) and got lucky. The trace file showed an interesting “unparsed SQL” statement which, stripped of double-quote marks and re-formatted, was as follows (in 18.104.22.168 – this may vary with version of Oracle):
SELECT A.DUMMY QCSJ_C000000000600000, from$_subquery$_007.DUMMY_0 QCSJ_C000000000600001, from$_subquery$_007.ROWID_1 ROWID FROM SYS.DUAL A, LATERAL( ( SELECT D.DUMMY DUMMY_0, D.ROWID ROWID_1 FROM ( SELECT from$_subquery$_005.QCSJ_C000000000500001_1 DUMMY, from$_subquery$_005.QCSJ_C000000000500003_2 ROWID FROM ( SELECT B.DUMMY QCSJ_C000000000500000, C.DUMMY QCSJ_C000000000500001_1, B.ROWID QCSJ_C000000000500003_2 FROM SYS.DUAL B, SYS.DUAL C WHERE B.DUMMY=C.DUMMY ) from$_subquery$_005 ) D WHERE A.DUMMY=D.DUMMY ) )(+) from$_subquery$_007
Note the alias of ROWID appearing in lines 4 and 15. If you tried to run this SQL from the command line (after fiddling the event to enable lateral() views), or even just the simple select running from lines 13 to 26, you would get error ORA-00923: FROM keyword not found where expected. My guess is that the context in which the optimisation takes place means that this error is re-raised as the error ORA-01445 that we ultimately see.