Sql server 在SQL Server中更新表中除一条以外的所有重复记录

Sql server 在SQL Server中更新表中除一条以外的所有重复记录,sql-server,Sql Server,我有一个SQL Server表,其中一列对象id中有重复的条目,例如: 我需要更新他们的所有状态,除了在object_id列中存在重复时的状态。因此,在上面的表中,对象_id 1和3是重复的。所以我想把他们的状态值改为2,除了其中一个条目。结果如下: | id | object_id | status_val | +----+-----------+------------+ | 1 | 1 | 0 | | 2 | 1 |

我有一个SQL Server表,其中一列对象id中有重复的条目,例如:

我需要更新他们的所有状态,除了在object_id列中存在重复时的状态。因此,在上面的表中,对象_id 1和3是重复的。所以我想把他们的状态值改为2,除了其中一个条目。结果如下:

| id | object_id | status_val |
+----+-----------+------------+
|  1 |         1 |          0 | 
|  2 |         1 |          2 | 
|  3 |         1 |          2 | 
|  4 |         2 |          0 | 
|  5 |         3 |          0 | 
|  6 |         3 |          2 | 
+----+-----------+------------+
哪一个复制行的状态已更新并不重要


任何帮助都将不胜感激。

您无需加入即可解决此问题,这意味着它应该具有更好的性能。其思想是按对象id对数据进行分组,计算每个对象id的行数。这就是分区所做的。然后可以更新行数>1的位置。这将更新除第一个对象外的所有重复对象id

UPDATE Table
SET Table.status_val = '2'
FROM Table
INNER JOIN
(SELECT id, row_number()OVER(PARTITION BY object_id ORDER BY id) as seq FROM Table) other_table
ON Table.id = other_table.id AND seq <> 1
update t set t.status_val = 'some_status' 
from (
    select *, row_number() over(partition by object_id order by (select null)) row_num  
    from foo
) t 
where row_num > 1 
在82944条记录的测试表上,性能是如此之高,您的里程数可能会有所不同!: 表“测试”。扫描计数5,逻辑读取82283,物理读取0,预读0,lob逻辑读取0,lob物理读取0,lob预读0。 CPU时间=141毫秒,运行时间=150毫秒

我们当然也可以通过使用内部联接来解决此问题,但是,通常这会导致更多的逻辑读取和更高的CPU:

表“测试”。扫描计数10,逻辑读取83622,物理读取0,预读0,lob逻辑读取0,lob物理读取0,lob预读0。 表“工作文件”。扫描计数0,逻辑读取0,物理读取0,预读读取0,lob逻辑读取0,lob物理读取0,lob预读读取0。 表“工作台”。扫描计数4,逻辑读取167426,物理读取0,预读0,lob逻辑读取0,lob物理读取0,lob预读0。 CPU时间=342毫秒,运行时间=233毫秒

要循环显示结果并以较小的批更新,请执行以下操作:

declare @rowcount int = 1;
declare @batch_size int = 1000;

while @rowcount > 0 
begin
    update top(@batch_size) t set t.status_val = 'already updated'
    from (
        select *, row_number() over(partition by object_id order by (select null)) row_num  
        from foo
        where status_val <> 'already updated' 
    ) t 
    where row_num > 1 
    set @rowcount = @@rowcount;
end

如果其他并发会话试图访问此表,这将有助于保持锁定

根据您的问题,似乎对于object_id的每个值,您希望将id最低的object_id的状态_val=0,其他的保持状态_val=2。如果确实如此,并且如果一个对象id最多只重复3次,那么我有一个非常简单的解决方案。使用模运算符或余数运算符获得所需的值。以下是我稍后将解释的答案:

update [MyTable]
set status_val = 2
where (id%3) != 1
将id的任何值除以3时,余数只能是0、1或2。因此,对于id%3不是1的每个对象,我们将状态值更改为2

在执行上述代码之前,请参阅此查询的输出-

select id, (id%3) as flg, object_id, status_val 
from MyTable

看我的答案,它很小很简单。谢谢你的回答。我在周末测试了这个,效果很好!再次谢谢。嗨。事实上,我试着用一个更大的数据集来测试它,发现它花费的时间太长了。表中有超过200万个条目,并且查询已经运行了3个多小时。有没有一种方法可以批量更新,这样就不会同时在整个表上运行?也许我可以从单独的独立windows服务运行它?这可能是提交大小的bc。只要状态值可以过滤掉已经更新的行,就可以在循环中执行此操作。我将使用循环选项更新我的答案。
select id, (id%3) as flg, object_id, status_val 
from MyTable