如何使用ORDER BY更新TOP(n)以获得可预测的结果?
如何使用ORDER BY更新TOP(n)以获得可预测的结果?
我试图读取一个被用作队列的数据库表的前100个项目。在这个过程中,我尝试将这些项目标记为已完成,方法如下:\n
UPDATE TOP(@qty) QueueTable WITH (READPAST) SET IsDone = 1 OUTPUT inserted.Id, inserted.Etc FROM QueueTable WHERE IsDone = 0 ORDER BY CreatedDate ASC;
\n唯一的问题是,根据MSDN上的UPDATE (Transact-SQL),在UPDATE中ORDER BY
是无效的,且:\n
\n在INSERT、UPDATE或DELETE中与TOP表达式一起使用的行没有以任何顺序排列。\n
\n我该如何实现我需要的操作,即更新队列顶部的项目并选择它们?
问题出现的原因是在使用ORDER BY对TOP(n)进行更新时,结果可能是不确定的。解决方法是使用排名函数(例如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
以上代码使用了排名函数row_number(),并通过对CreatedDate进行升序排序来保证更新结果的可预测性。在更新之前,首先将需要更新的数据进行排序,并为每一行数据分配一个排名。然后,通过设置WHERE子句来筛选出排名小于等于100的数据进行更新。更新操作完成后,可以通过OUTPUT子句来获取更新后的数据。
通过以上方法,我们可以在使用ORDER BY对TOP(n)进行更新时,获得可预测的结果。
在SSMS中经过测试,它可以正常工作。您可能需要根据需要进行一些修改。
原因:问题的出现是因为在使用UPDATE TOP(n)语句时,如果没有指定ORDER BY子句,更新的顺序是不确定的。这可能导致每次运行查询时都会得到不同的结果。
解决方法:为了使UPDATE TOP(n)语句具有可预测的结果,可以通过在UPDATE语句中添加ORDER BY子句来指定更新的顺序。以下是解决方法的代码示例:
-- 创建表结构 create table #temp1 ( id int identity(1,1), value int ) -- 插入示例数据 insert #temp1 values (1) go 20 -- 解决方法 declare @n int = 10 declare @sql nvarchar(2000) = N'update top '+ cast(@n as nvarchar(5)) +' #temp1 set value = 100 output inserted.value where id in ( select top '+ cast(@n as nvarchar(5)) +' id from #temp1 order by id )' execute sp_executesql @sql
通过在UPDATE语句中添加ORDER BY子句,并使用嵌套的SELECT语句来限制更新的记录数量,可以确保UPDATE TOP(n)语句的结果是可预测的。在上述示例中,我们通过指定ORDER BY id来按id字段的升序对记录进行排序,并使用嵌套的SELECT语句选择前10个id值进行更新。这样,每次运行查询时,都会按照相同的顺序更新相同的记录。
问题的原因是,用户想要在更新操作中使用ORDER BY子句来指定顺序,并且只更新前N条记录。用户希望能够预测更新的结果。
解决方法是在UPDATE语句中使用派生表、CTE或视图。首先,用户创建一个派生表或CTE,使用ORDER BY子句来指定顺序,并使用TOP(N)来限制记录的数量。然后,在UPDATE语句中使用FROM子句来引用这个派生表或CTE,并设置需要更新的列和输出的列。
下面是一个示例代码:
UPDATE x SET IsDone = 1 OUTPUT inserted.Id, inserted.Etc FROM ( SELECT TOP (N) * FROM QueueTable WHERE IsDone = 0 ORDER BY CreatedDate ASC ) x
这种方法比先计算一组ID再进行更新更快,并且通常具有更可取的锁定行为。
评论中提到,这种方法适用于任何表达式,并且在SQL Server 2005中引入了top ()
。此外,这种方法的锁定行为与通常的更新操作相同,不需要额外的锁定操作。虽然这种方法没有官方文档支持,但很多人使用它并且经过验证。
,用户可以使用派生表、CTE或视图来实现在更新操作中使用ORDER BY子句和TOP(N),并且可以预测更新的结果。这种方法在SQL Server 2005及更高版本中可用,并且具有与通常更新操作相同的锁定行为。