2012-11-30 190 views
67

我想用增量编号更新我的列CODE_DEST。我有:带有row_number的SQL更新()

CODE_DEST RS_NOM 
null  qsdf 
null  sdfqsdfqsdf 
null  qsdfqsdf 

我想更新它是:

CODE_DEST RS_NOM 
1   qsdf 
2   sdfqsdfqsdf 
3   qsdfqsdf 

我曾尝试这样的代码:

UPDATE DESTINATAIRE_TEMP 
SET CODE_DEST = TheId 
FROM (SELECT Row_Number() OVER (ORDER BY [RS_NOM]) AS TheId FROM DESTINATAIRE_TEMP) 

这并不是因为)

工作

我也试过:

WITH DESTINATAIRE_TEMP AS 
    (
    SELECT 
    ROW_NUMBER() OVER (ORDER BY [RS_NOM] DESC) AS RN 
    FROM DESTINATAIRE_TEMP 
) 
UPDATE DESTINATAIRE_TEMP SET CODE_DEST=RN 

但是这也因为工会而不起作用。

如何使用SQL Server 2008 R2中的ROW_NUMBER()函数更新列?

+0

后的样本数据和预期的结果,那就是得到一个SQL的最佳方式回答。否则你的?没有任何意义,并会产生这样的答案'UPDATE myCol = myCol + 1 FROM MyTable WHERE ID = @ MyID' – JonH

回答

33
With UpdateData As 
(
SELECT RS_NOM, 
ROW_NUMBER() OVER (ORDER BY [RS_NOM] DESC) AS RN 
FROM DESTINATAIRE_TEMP 
) 
UPDATE DESTINATAIRE_TEMP SET CODE_DEST = RN 
FROM DESTINATAIRE_TEMP 
INNER JOIN UpdateData ON DESTINATAIRE_TEMP.RS_NOM = UpdateData.RS_NOM 
+1

这只适用于RS_NOM列中的值是唯一的,不是吗?我怀疑这是可以假设的。 – Toby

112

还有一个选项

UPDATE x 
SET x.CODE_DEST = x.New_CODE_DEST 
FROM (
     SELECT CODE_DEST, ROW_NUMBER() OVER (ORDER BY [RS_NOM]) AS New_CODE_DEST 
     FROM DESTINATAIRE_TEMP 
    ) x 
+0

令人困惑的是,您有两个名为x的变量。重命名第一个变量并编辑你的答案。 – Craig

+14

@Craig:你说“两个变量名为x”是什么意思?这个UPDATE语句不引用任何变量。在这个解决方案中只有一个名为* x *的事物,它是在FROM子句中定义的派生表。这里没有什么不明确的地方。也许语法对你而言并不熟悉,但是没关系,你可以解释一下你对它的疑惑,并希望得到一个清除你的困惑的回应(如果手册没有帮助的话)。 –

+0

这是一个明智的答案,还是SQL Server可以在嵌套SELECT内更新的辉煌?我认为这两者都是...... – Bigjim

10

,因为你被点名的CTE相同基础表和取得的CTE看起来好像是一个递归CTE你的第二次尝试主要是失败的,因为它本质上引用它自己。 A recursive CTE必须具有需要使用UNION ALL集合运算符的特定结构。

相反,你可以只给热膨胀系数不同的名称,以及添加的目标列到它:

With SomeName As 
(
SELECT 
CODE_DEST, 
ROW_NUMBER() OVER (ORDER BY [RS_NOM] DESC) AS RN 
FROM DESTINATAIRE_TEMP 
) 
UPDATE SomeName SET CODE_DEST=RN 
0

简单易用的方式来更新光标

UPDATE Cursor 
SET Cursor.CODE = Cursor.New_CODE 
FROM (
    SELECT CODE, ROW_NUMBER() OVER (ORDER BY [CODE]) AS New_CODE 
    FROM Table Where CODE BETWEEN 1000 AND 1999 
) Cursor 
6

这@Aleksandr费德林的回答修改后的版本添加一个WHERE子句:

UPDATE x 
SET x.CODE_DEST = x.New_CODE_DEST 
FROM (
     SELECT CODE_DEST, ROW_NUMBER() OVER (ORDER BY [RS_NOM]) AS New_CODE_DEST 
     FROM DESTINATAIRE_TEMP 
    ) x 
WHERE x.CODE_DEST <> x.New_CODE_DEST AND x.CODE_DEST IS NOT NULL 

通过添加一个WHERE子句,我发现性能后续更新极大的改进。即使该值已经存在,Sql Server似乎也会更新该行,并且需要时间才能这样做,因此添加where子句可以跳过值未改变的行。我不得不说,我惊讶于它可以运行我的查询有多快。

声明:我不是数据库专家,我使用PARTITION BY作为我的子句,因此它可能不完全相同的结果为此查询。对于我来说,所讨论的列是客户的付款订单,所以一旦设置它,价值一般不会改变。

还要确保你有索引,特别是如果你在SELECT语句上有WHERE子句。过滤索引对我来说非常适合,因为我是基于付款状态进行过滤的。


我通过

UPDATE UpdateTarget 
SET  PaidOrderIndex = New_PaidOrderIndex 
FROM 
(
    SELECT PaidOrderIndex, SimpleMembershipUserName, ROW_NUMBER() OVER(PARTITION BY SimpleMembershipUserName ORDER BY OrderId) AS New_PaidOrderIndex 
    FROM [Order] 
    WHERE PaymentStatusTypeId in (2,3,6) and SimpleMembershipUserName is not null 
) AS UpdateTarget 

WHERE UpdateTarget.PaidOrderIndex <> UpdateTarget.New_PaidOrderIndex AND UpdateTarget.PaidOrderIndex IS NOT NULL 

-- test to 'break' some of the rows, and then run the UPDATE again 
update [order] set PaidOrderIndex = 2 where PaidOrderIndex=3 

使用分区查询中的 'IS NOT NULL' 没有如果列不可为空所需的部分。


当我说性能增加量很大时,我的意思是在更新少量行时基本上是瞬时的。有了正确的指标,我能够做到这一点花的时间相同的“内部”查询的更新确实本身:

SELECT PaidOrderIndex, SimpleMembershipUserName, ROW_NUMBER() OVER(PARTITION BY SimpleMembershipUserName ORDER BY OrderId) AS New_PaidOrderIndex 
    FROM [Order] 
    WHERE PaymentStatusTypeId in (2,3,6) and SimpleMembershipUserName is not null 
+1

这是一个非常有趣的观点。谢谢 –

+0

@AleksandrFedorenko老实说,我很惊讶它的工作,但很高兴它做了:)索引是我创建的重要 –