3

I'm trying to read the top 100 items of a database table that is being used like a queue. As I do this I'm trying to mark the items as done like this:

UPDATE TOP(@qty)
    QueueTable WITH (READPAST)  
SET 
    IsDone = 1
OUTPUT
    inserted.Id,
    inserted.Etc
FROM
    QueueTable 
WHERE
    IsDone = 0
ORDER BY
    CreatedDate ASC;

The only problem is, according to UPDATE (Transact-SQL) on MSDN, the ORDER BY is not valid in an UPDATE and:

The rows referenced in the TOP expression used with INSERT, UPDATE, or DELETE are not arranged in any order.

How can I achieve what I need which is to update the items at the top of the queue while also selecting them?

Martin Brown
  • 24,692
  • 14
  • 77
  • 122
  • 1
    Can you use TOP with ORDER BY to get a list of Unique ID's which will be the top 100 (sorted / ordered) rows and only update the table where they contain these IDs? Here's an example with a CTE: http://stackoverflow.com/a/9241466/6167855 – S3S Nov 17 '16 at 17:18
  • Does this answer your question? [how can I Update top 100 records in sql server](https://stackoverflow.com/questions/1198364/how-can-i-update-top-100-records-in-sql-server) – Michael Freidgeim Jun 08 '22 at 11:07

3 Answers3

9

SQL Server allows you to update a derived table, CTE or view:

UPDATE x
SET 
    IsDone = 1
OUTPUT
    inserted.Id,
    inserted.Etc
FROM (
select TOP (N) *
FROM
    QueueTable 
WHERE
    IsDone = 0
ORDER BY
    CreatedDate ASC;
) x

No need to compute a set of IDs first. This is faster and usually has more desirable locking behavior.

usr
  • 168,620
  • 35
  • 240
  • 369
0

Tested in SSMS, it works fine. You may need to do some modification accordingly.

--create table structure
create table #temp1 (
    id int identity(1,1),
    value int
)
go

--insert sample data
insert #temp1 values (1)
go 20


--below is solution
declare @qty int = 10
declare @cmd nvarchar(2000) =
N'update #temp1
set value= 100
output inserted.value
where id in
(
    select top '+ cast(@qty as nvarchar(5)) +' id from #temp1
    order by id
)';

execute sp_executesql @cmd
Dance-Henry
  • 923
  • 1
  • 7
  • 11
0

You can use ranking function (for example row_number).

update top (100) q
set IsDone = 1
output
    inserted.Id,
    inserted.Etc
from (
    select *, row_number() over(order by CreatedDate asc, (select 0)) rn
    from QueueTable) q
where rn <= 100
Deadsheep39
  • 561
  • 3
  • 16