views:

130

answers:

2

The answer to another SO question was to use this SQL query:

SELECT o.Id, o.attrib1, o.attrib2 
  FROM table1 o
  JOIN (SELECT DISTINCT Id 
          FROM table1, table2, table3 
         WHERE ...) T1 ON o.id = T1.Id

Now I wonder how I can use this statement together with the keyword FOR UPDATE. If I simply append it to the query, Oracle will tell me:

ORA-02014: cannot select FOR UPDATE from view

Do I have to modify the query or is there a trick to do this with Oracle? With MySql the statement works fine.

+4  A: 

try:

select ..... 
from <choose your table>
where id in (<your join query here>) for UPDATE;

EDIT: that might seem a bit counter-intuitive bearing in mind the question you linked to (which asked how to dispense with an IN), but may still provide benefit if your join returns a restricted set. However, there is no workaround: the oracle exception is pretty self-explanatory; oracle doesn't know which rows to lock becasue of the DISTINCT. You could either leave out the DISTINCT or define everything in a view and then update that, if you wanted to, without the explicit lock: http://www.dba-oracle.com/t_ora_02014_cannot_select_for_update.htm

davek
This was the origin of my other SO question. This statement is very slow with MySql, so I tried to replace it with the explicit JOIN statement.
tangens
@tangens: As I said in my other answer, trying to write a single query that works in all RDBMS and trying to get good performance are often opposing factors. If one thing works best for MySQL and another for Oracle, it's probably best to just write two slightly different queries.
Mark Byers
Trying to write a query which will "work well in all RDBMS" is a big task, as you not only need to cater for mysql/oracle/sql server/postgres, you also need to cater for the different versions. Something which runs fine in oracle 11g might run like complete rubbish in oracle 9i.
Matthew Watson
"it's probably best to just write two slightly different queries." That's the way I will do it.
tangens
A: 

It may depend what you want to update. You can do ... FOR UPDATE OF o.attrib1 to tell it you're only interested in updating data from the main table, which seems likely to be the case; this means it will only try to lock that table and not worry about the implicit view in the join. (And you can still update multiple columns within that table, naming one still locks the whole row - though it will be clearer if you specify all the columns you want to update in the FOR UPDATE OF clause).

Don't know if that will work with MySQL though, which brings us back to Mark Byers point.

Alex Poole
With "FOR UPDATE OF o.Id" I get the error "ORA-01786 FOR UPDATE of this query expression is not allowed".
tangens
Strange, I can't get that error unless I make add a DISTINCT or some kind of grouping or union to the outer SELECT. Under 9i, in SQL*Plus or PL/SQL.
Alex Poole