You could try using a processed/read column on the table - and updating that column and output the selected data.
Declare @sourceTable Table (col1 int, col2 int, col3 int, readFlag bit Not Null);
Insert Into @sourceTable (col1, col2, col3, readFlag)
Values (1, 1, 1, 0)
, (2, 2, 2, 0)
, (3, 3, 3, 0)
, (4, 4, 4, 0)
, (5, 5, 5, 0)
, (11, 1, 1, 0)
, (12, 2, 2, 0)
, (13, 3, 3, 0)
, (14, 4, 4, 0)
, (15, 5, 5, 0)
, (21, 1, 1, 0)
, (22, 2, 2, 0)
, (23, 3, 3, 0)
, (24, 4, 4, 0)
, (25, 5, 5, 0);
Select *
From @sourceTable st;
--==== First process calls this...
Declare @outputTable Table (col1 int, col2 int, col3 int);
Update Top (5)
@sourceTable
Set readFlag = 1
Output inserted.col1, inserted.col2, inserted.col3 Into @outputTable
Where readFlag = 0
Select *
From @outputTable ot;
Select *
From @sourceTable st;
--==== For testing a second call - we clear the output table and update the next set of rows.
--==== this is only for testing and would not be part of the solution
Delete From @outputTable;
Update Top (5)
@sourceTable
Set readFlag = 1
Output inserted.col1, inserted.col2, inserted.col3 Into @outputTable
Where readFlag = 0
Select *
From @outputTable ot;
Select *
From @sourceTable st;
The UPDATE will lock the rows it needs to lock - update the values - then you return the rows that were updated to the client for further processing. The second client will be blocked until the first client is done updating, then select the next 5 rows and return to that client for further processing.
You should not have any problems with isolation levels as the update will lock the rows - and subsequent updates will need to wait for an update lock.