使用游标基于子查询更新数据库的替代方法

Alternatives to using cursor for updating a database based on a subquery

也许这个标题并不是很有启发性,但我不能想出一个不那么做作的标题。这是我的问题:

我正在使用 table 的数据看起来像

id  cId        ver      active
1   100         1       0    
2   100         2       1    
3   100         3       1    
4   200         1       0    
5   200         2       1    
6   300         1       1

对于此table,Id 是主键,cId 标识客户端。基本上我们正在存储版本控制历史。

我试图解决的问题是更新数据库以仅对最新版本设置 active =1,这是每个客户端的最高 [ver]。 (cId 为 100 的客户端在示例中被窃听)

现在,我已经设法编写了以下查询,为我提供了可以处理的数据

select t.id, t.cId,t.version 
from (select *
      from comp.Clients  a
      where a.ver = (select max(b.ver) from comp.Clients b where a.cId=b.cIdentifier)
    ) t

从那时起,我的解决方案是将该查询插入游标,对于游标上的每条记录,我会将当前记录的 table 更新为 active=0 和 active =1。

问题是游标就是它们的本质,有没有什么东西可以让我在这里有不错的表现?我不擅长 CTE,所以我无法提出围绕它的解决方案。实际 table 有大约 10k 条记录和大约 50 个字段。

您应该为每个 CId 找到最后一个 ver,然后更新您的 table

select cId,Max(ver) as MaxVer into #tmpTable from comp.Clients  group by cid

update c
set active = case when t.cId is not null then 1 else 0 end
from comp.Clients c left join #tmpTable t on t.CId=c.CId and t.MaxVer=c.ver

不使用游标,而是使用 2 个更新。一个将值更新为 0,另一个将客户端 ID 的最新版本设置为 1。这应该足够了。

使用可更新的 CTE:

with toupdate as (
      select c.*,
             max(ver) over (partition by CId) as max_ver
      from comp.Clients c
     )
update toupdate
    set active = (case when max_ver = ver then 1 else 0 end);

您可以添加一个 where 子句来限制要更新的行数,如果您愿意的话:

   where active <> (case when max_ver = ver then 1 else 0 end)