update mytable set node_index=0 where id in ( SELECT id FROM mytable WHERE rownum<=10 and PROCS_DT is null order by CRET_DT,PRTY desc)
I got this query as part of a previous answer to my question. Now how to lock the rows in the select query to make sure no other thread over writes my update.
Advertisement
Answer
It’s not clear to me that you have the problem you seem to think you have.
Updating a row in the table inherently places a row-level lock on that row. No other session can update that row until you release the lock by ending your transaction by committing or rolling back. Once you complete your transaction, other sessions are free to overwrite your update. There is no need or benefit to locking the rows in the SELECT
.
If you are trying to write your application to avoid lost updates (i.e. you want to avoid another session updating the same rows that you did after you committed your transaction without showing the other user your updated data first), your application would need to implement some sort of additional locking. The most efficient would be to implement optimistic locking using some sort of LAST_UPDATE_TIMESTAMP
column in the table. Assuming you added this column to the table if it doesn’t already have one, you would select the LAST_UPDATE_TIMESTAMP
whenever you queried data to present to the user and you would specify that LAST_UPDATE_TIMESTAMP
in your UPDATE
. If your UPDATE
updated exactly 1 row, you know that no one had changed the data since you queried it. If your UPDATE
updated 0 rows, you would know that the data had changed since you had queried it and your application would need to take appropriate action (i.e. re-querying the data, re-presenting it to the user, asking the user whether to keep any of the uncommitted changes they had made, etc.).
Your query does have another problem, however. The SELECT
statement is almost certainly not doing what you think (or intend) for it to do. This query gets an arbitrary 10 rows from MYTABLE
where PROCS_DT
is NULL and then orders those arbitrary 10 rows.
SELECT id FROM mytable WHERE rownum<=10 and PROCS_DT is null order by CRET_DT,PRTY desc
Assuming that you actually want to get the “top 10” results, you would need to do the ORDER BY
in a subquery before applying the ROWNUM
predicate, i.e.
SELECT id FROM (SELECT * FROM mytable WHERE procs_dt IS NULL ORDER BY cret_dt, prty desc) WHERE rownum<=10
Or you could use an analytic function, i.e.
SELECT id FROM (SELECT m.*, rank() over (ORDER BY cret_dt, prty desc) rnk FROM mytable m WHERE procs_dt IS NULL) WHERE rnk<=10