views:

269

answers:

5

If I want to select all records in a table that have not been processed yet and then update those records to reflect that they have been processed, I would do the following:

 SELECT * FROM [dbo].[MyTable] WHERE [flag] IS NULL;
 UPDATE [dbo].[MyTable] SET [flag] = 1 WHERE [flag] IS NULL;

How do I ensure that the UPDATE works on only the records I just selected, ie, prevent the UPDATE of any records that may have been added with [flag] = NULL that occurred AFTER my SELECT but before my UPDATE by another process? Can I wrap those two statements in a transaction? Do I have to put a lock on the table?

A: 

Assuming that [flag] is a bit field. I would:

Update [myTable] set flag = 0 where flag is null;
select * from [mytable] where flag = 0;
Update [mytable] set flag = 1 where flag = 0;
Avitus
+1 Just what I was in the process of typing up. This two phase update is a really handy way of addressing this issue.
David Hall
Isn't this just removing the problem one level? Another process could run the Update to 0 in between the first process' update and select.
womp
+2  A: 

You can wrap these two statements in a transaction with read_committed or more restricted scope. Its a bit expensive and might cause other issues. King's solution is more workable.

GrayWizardx
+2  A: 

Use:

SELECT * 
  FROM [dbo].[MyTable] (UPDLOCK)
 WHERE [flag] IS NULL;

UPDATE [dbo].[MyTable] 
   SET [flag] = 1 
 WHERE [flag] IS NULL;

For more info on locking hints:

OMG Ponies
+1. Note that this would need to be in a transaction for the update lock to carry through to the update statement.
womp
Still 2 statements though that aren't needed with SQL Server 2005 +
gbn
+3  A: 

Use the OUTPUT clause to return a result set from the UPDATE itself:

UPDATE [dbo].[MyTable] 
SET [flag] = 1 
OUTPUT INSERTED.*
WHERE [flag] IS NULL;
Remus Rusanu
+3  A: 

Single call, no transaction needed by using the OUTPUT clause.

XLOCK exclusively locks the rows to stop concurrent reads (eg another process looking for NULL rows)

UPDATE dbo.MyTable WITH (XLOCK)
SET flag = 1 
OUTPUT INSERTED.*
WHERE flag IS NULL;
gbn
What's the earliest version of SQL Server that supports the `OUTPUT` clause?
OMG Ponies
SQL Server 2005, which should be a fair assumption to make in (almost) 2010...
gbn
..and given OP uses SSIS too, based on other questions.
gbn
yes, i was interested in 2k5, sorry, i should've mentioned that. this looks like the winner for my purposes -- thanks!
heath