I'm running into the following issue in Oracle SQL. gt_general2 is a global temp table.
INSERT INTO gt_general2 (n_1, n_2, n_3)
select p.x_id, a.y_id, a.dollar_amt
from table_P p, table_A a
where p.x_id = a.x_id
and a.h_date = i_date
and a.dollar_amt > 0
for update of p.x_id, a.dollar_amt nowait; --this is the problem statement
Oracle doesn't like when I try to use the INSERT…SELECT syntax with the SELECT… FOR syntax.
I would like to lock the rows while doing this insert because the real query is actually fairly complex (and does some checks against other views to make sure parent records exist, etc.) and this way I can insert into the temp table while doing the row lock in a single pass.
Is there some other syntax I'm missing that would allow me to do this? On a conceptual level, I don't see any reason why Oracle wouldn't allow me to select rows from tables P and A, lock them in the process, and insert the values into another table Z. I already can do this after all:
select p.x_id, a.y_id
BULK COLLECT into x_id_list, y_id_list
from table_P, table_A
where ...
for update nowait;
It's of course possible to lock the rows by doing this query twice- once to lock, and once to insert. Previously, I did this and used the lock query to retrieve the "x_id" values in an array to help out the INSERT INTO query. But the problem I ran into was that the x_id value wasn't enough to identify the rows I wanted properly; I needed the pair of (x_id, y_id) and can't create a new nested table type to store it.
Best Answer
You can't combine an
INSERT
with aSELECT FOR UPDATE
in a single statement. You can however use a regularSELECT FOR UPDATE
and use bulk collect with bulk insert to achieve nearly similar performance.You also don't need to create a new permanent SQL type object if you declare the collection in the PL/SQL code.
Here's an example, first the setup:
The lock and insert procedure (tested on 11.2.0.2.0):
This will do bulk select/insert in batches of 100 rows in a single pass. This should be faster than a lock statement followed by an insert statement. Plus you're guaranteed that the rows inserted are exactly the same as the rows locked (whereas the two statements executed one after the other could return inconsistent results if the table has been modified).