【问题标题】:SQL Update with row_number()使用 row_number() 进行 SQL 更新
【发布时间】:2023-04-11 03:19:01
【问题描述】:

我想用递增的数字更新我的列 CODE_DEST。我有:

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() 函数更新列?

【问题讨论】:

  • 发布示例数据和预期结果,这是获得 SQL 答案的最佳方式。否则你的 ?没有意义,会产生这样的答案UPDATE myCol = myCol+1 FROM MyTable WHERE ID=@MyID

标签: sql-server sql-server-2008-r2 sql-update


【解决方案1】:

我用第一次出现的部分更新了一个临时表,其中多个部分可以与一个序列号相关联。 RowId=1 返回我使用部分和序列号加入 tmp 表和数据的第一次出现。

update #Tmp
set 
#Tmp.Amount=@Amount
from 
(SELECT Part, Row_Number()   OVER (ORDER BY [Part]) AS RowId FROM #Tmp
where Sequence_Num=@Sequence_Num
)data
where data.Part=#Tmp.Part
and data.RowId=1
and #Tmp.Sequence_Num=@Sequence_Num

【讨论】:

    【解决方案2】:

    在我的例子中,我添加了一个新列,并想用整个表的 equevilat 记录号对其进行更新

    id  name       new_column (ORDER_NUM)
    1   Ali        null
    2   Ahmad      null
    3   Mohammad   null
    4   Nour       null
    5   Hasan      null
    6   Omar       null
    

    我编写此查询是为了在新列中填充行号

    UPDATE My_Table
    SET My_Table.ORDER_NUM  = SubQuery.rowNumber
    FROM (
             SELECT id ,ROW_NUMBER() OVER (ORDER BY [id]) AS rowNumber
             FROM My_Table
         ) SubQuery
    INNER JOIN My_Table ON
            SubQuery.id = My_Table.id
    

    执行此查询后,我的新列中有 1,2,3,... 数字

    【讨论】:

      【解决方案3】:

      更多选择

      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
      

      【讨论】:

      • 这是一个绝妙的答案,还是 SQL Server 可以在嵌套的 SELECT 中更新是绝妙的?我认为两者都是....
      • 您可以使用 WHERE 子句大幅提高未来的更新性能(请参阅我基于此的答案)
      • 这就像一个魅力!谢谢 :) 我在我的子表中添加了一个排序字段,并希望为每个主键组分配顺序排序,它工作得很棒。
      【解决方案4】:

      如果表没有关系,只需将所有行号复制到新表中并删除旧表并用旧表重命名新表。

      Select   RowNum = ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) , * INTO cdm.dbo.SALES2018 from 
      (
      select * from SALE2018) as SalesSource
      

      【讨论】:

        【解决方案5】:

        我是根据我的情况这样做的,并且工作过

        WITH myUpdate (id, myRowNumber )
        AS
        ( 
            SELECT id, ROW_NUMBER() over (order by ID) As myRowNumber
            FROM AspNetUsers
            WHERE  UserType='Customer' 
         )
        
        update AspNetUsers set EmployeeCode = FORMAT(myRowNumber,'00000#') 
        FROM myUpdate
            left join AspNetUsers u on u.Id=myUpdate.id
        

        【讨论】:

          【解决方案6】:

          这是@Aleksandr Fedorenko 答案的修改版本,添加了 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 子句时。当我根据付款状态进行过滤时,过滤索引对我来说非常有用。


          我的查询使用 PARTITION by

          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
          

          【讨论】:

          • @AleksandrFedorenko 老实说,我很惊讶它起作用了,但很高兴它起作用了 :) 我创建的索引也很重要
          • 感谢这个有用的提示。最好的问候。
          【解决方案7】:

          您的第二次尝试失败主要是因为您将 CTE 命名为与基础表相同,并使 CTE 看起来像是 递归 CTE,因为它本质上引用了自己。 recursive CTE 必须具有特定的结构,该结构需要使用 UNION ALL 集合运算符。

          相反,您可以为 CTE 指定一个不同的名称,并将目标列添加到其中:

          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
          

          【讨论】:

            【解决方案8】:
            DECLARE @id INT 
            SET @id = 0 
            UPDATE DESTINATAIRE_TEMP
            SET @id = CODE_DEST = @id + 1 
            GO 
            

            试试这个

            http://www.mssqltips.com/sqlservertip/1467/populate-a-sql-server-column-with-a-sequential-number-not-using-an-identity/

            【讨论】:

            • 以上只有一项在 SQL Server 2012 中对我有用
            • 不错的答案!尝试:SET CODE_DEST = @id, @id = @id + 1 以提高可读性。
            • 整洁,但这仅适用于定义的子集,因此它在缩放方面的应用有限。如果你想更新两组数据并在这两种情况下迭代这个值,这将需要一个循环。
            【解决方案9】:

            更新光标的简单方法

            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
            

            【讨论】:

              【解决方案10】:
              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
              

              【讨论】:

              • 这仅在 RS_NOM 列中的值是唯一的情况下才有效,不是吗?我怀疑这是可以假设的。
              猜你喜欢
              • 2022-01-16
              • 2021-12-14
              • 1970-01-01
              • 1970-01-01
              • 2017-07-31
              • 2012-08-23
              • 2011-03-13
              • 1970-01-01
              相关资源
              最近更新 更多