Skip to content
Advertisement

Update Query with select and row lock

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 
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement