【问题标题】:Update SQL with consecutive numbering使用连续编号更新 SQL
【发布时间】:2009-07-22 20:03:46
【问题描述】:

我想更新一个从 1 开始连续编号的表。更新有一个 where 子句,因此只有满足该子句的结果才会重新编号。我可以在不使用临时表的情况下有效地完成这项工作吗?

【问题讨论】:

  • 这很可能取决于您运行的特定 SQL 版本,我认为没有标准的方法可以做到这一点。
  • 这个号码有什么用途?你在创建一个ID吗?另外,我不会担心效率低下。如果没有其他信息,听起来您不会因为效率低下而错过某些东西。听起来像是一次性手术。
  • 我每周在 2 GB 管道分隔文件中获得 150 万个列表。我需要运行一个存储过程来确定哪些列表在我的客户城市中,给他们客户 ID,并为每个客户按顺序编号。它必须是有效的。
  • 现在我明白了你为什么要编号,我提出的解决方案不能满足你的需要。如果同时运行多个更新,您将不会在该更新中获得连续的数字。 +1 to zombat,我已经删除了我的答案。

标签: sql-server tsql


【解决方案1】:

这可能取决于您的数据库,但这里有一个涉及使用变量的 MySQL 5 解决方案:

SET @a:=0;
UPDATE table SET field=@a:=@a+1 WHERE whatever='whatever' ORDER BY field2,field3

您可能应该编辑您的问题并指出您正在使用的数据库。

编辑:我发现一个solution 使用 T-SQL for SQL Server。和 MySQL 的方法很像:

DECLARE @myVar int
SET @myVar = 0

UPDATE
  myTable
SET
  @myvar = myField = @myVar + 1

【讨论】:

  • 感谢您的帮助。因此,这将为更新找到的每条记录增加 myVar .. 太棒了!如果我的编号字段是 varchar 而不是 int 类型怎么办?我也可以将 myVar 转换为 varchar 吗?再次感谢大家!
  • 太棒了...从来不知道你能做到这一点。 +1
  • 我认为您可以毫无问题地使用 varchars...您绝对可以使用字符串变量。根据 SQL Server 使用字符串而不是整数处理数学的方式,您可能会在整个 SET 语句中面临几次转换,但我敢打赌这不会太难。
  • 注意,在带有 ORDER BY 子句的 SQL Server 查询中使用赋值操作具有未定义的行为。 connect.microsoft.com/SQLServer/Feedback/Details/383641marc.durdin.net/2015/07/…(这里讨论的是字符串,但可能会出现同样的问题)
  • 对于 MS Sql,您应该添加一个查询提示:OPTION (MAXDOP 1),如 stackoverflow.com/questions/1167885/… 建议的那样
【解决方案2】:

在 oracle 中这是有效的:

update myTable set rowColum = rownum
where something = something else

http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/pseudocolumns009.htm#i1006297

【讨论】:

    【解决方案3】:

    除了使用 CTE 或 WITH,还可以使用带有自连接的更新到同一个表:

    UPDATE a
    SET a.columnToBeSet = b.sequence
    FROM tableXxx a
    INNER JOIN
    (
       SELECT ROW_NUMBER() OVER ( ORDER BY columnX ) AS sequence, columnY, columnZ
       FROM tableXxx
       WHERE columnY = @groupId AND columnY = @lang2
    ) b ON b.columnY = a.columnY AND b.columnZ = a.columnZ
    

    派生表别名 b 用于通过 ROW_NUMBER() 函数与其他一些构成虚拟主键的列一起生成序列。 通常,每一行都需要一个唯一的序列值。

    WHERE 子句是可选的,它将更新限制在满足指定条件的那些行。

    然后将派生表连接到同一个表,别名为 a,连接到虚拟主键列,其中要更新的列设置为生成的序列。

    【讨论】:

      【解决方案4】:

      适用于 Microsoft SQL Server 2005/2008。 ROW_NUMBER() 函数于 2005 年添加。

      ; with T as (select ROW_NUMBER() over (order by ColumnToOrderBy) as RN
              , ColumnToHoldConsecutiveNumber from TableToUpdate
          where ...)
      update T
      set ColumnToHoldConsecutiveNumber = RN
      

      编辑:对于 SQL Server 2000:

      declare @RN int
      set @RN = 0 
      
      Update T
      set ColumnToHoldConsecutiveNubmer = @RN
          , @RN = @RN + 1
      where ...
      

      注意:当我测试 @RN 的增量似乎发生在将列设置为 @RN 之前,所以上面给出的数字从 1 开始。

      编辑: 我刚刚注意到您似乎想在表格中创建多个连续数字。根据要求,您可以通过在 over 子句中添加 partition by 来使用 SQL Server 2005/2008 一次性完成此操作:

      ; with T as (select ROW_NUMBER() 
              over (partition by Client, City order by ColumnToOrderBy) as RN
           , ColumnToHoldConsecutiveNumber from TableToUpdate)
      update T
      set ColumnToHoldConsecutiveNumber = RN
      

      【讨论】:

      • Shannon,当我需要为每个新组和子组重新启动增量数字时,您的最终编辑已经为我工作了好几次。谢谢你。你的答案应该排名更高。
      【解决方案5】:

      如果你想创建一个新的 PrimaryKey 列,只使用这个:

      ALTER TABLE accounts ADD id INT IDENTITY(1,1) 
      

      【讨论】:

        【解决方案6】:

        为了让香农的例子充分发挥作用,我不得不编辑他的答案:

        ; WITH CTE AS (
            SELECT ROW_NUMBER() OVER (ORDER BY [NameOfField]) as RowNumber, t1.ID
            FROM [ActualTableName] t1
        )
        UPDATE [ActualTableName]
            SET Name = 'Depersonalised Name ' + CONVERT(varchar(255), RowNumber)
        FROM CTE
            WHERE CTE.Id = [ActualTableName].ID
        

        因为他的回答是尝试更新 T,在他的例子中是通用表表达式的名称,它会引发错误。

        【讨论】:

          【解决方案7】:
          UPDATE TableName
          SET TableName.id = TableName.New_Id
          FROM (
            SELECT id, ROW_NUMBER() OVER (ORDER BY id) AS New_Id
            FROM TableName
            ) TableName
          

          【讨论】:

            【解决方案8】:

            多年来,我一直使用这种技术来填充序数和按顺序编号的列。但是,我最近在 SQL Server 2012 上运行时发现了一个问题。看起来查询引擎在内部使用多个线程应用更新,并且更新的谓词部分没有以线程安全的方式处理。为了让它再次工作,我不得不将 SQL Server 的最大并行度重新配置为 1 个核心。

            EXEC sp_configure 'show advanced options', 1;
            GO
            RECONFIGURE WITH OVERRIDE;
            GO
            EXEC sp_configure 'max degree of parallelism', 1;
            GO
            RECONFIGURE WITH OVERRIDE;
            GO
            
            DECLARE  @id int
            SET @id = -1
            UPDATE dbo.mytable
            SET @id = Ordinal = @id + 1
            

            如果没有这个,您会发现大多数序列号在整个表格中都是重复的。

            【讨论】:

            【解决方案9】:

            可能的,但只能通过一些非常复杂的查询 - 基本上你需要一个子查询来计算到目前为止选择的记录数,并将其用作序列 ID。我曾经写过类似的东西——它有效,但很痛苦。

            说实话,最好使用带有自动增量字段的临时表。

            【讨论】:

              【解决方案10】:

              加入数字表格?它涉及一个额外的表格,但它不会是临时的 - 您可以将数字表格作为实用程序保留。

              http://web.archive.org/web/20150411042510/http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-numbers-table.html

              http://www.sqlservercentral.com/articles/Advanced+Querying/2547/

              (后者需要免费注册,但我发现它是一个非常好的 MS SQL Server 提示和技术来源,并且很多适用于任何 SQL 实现)。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2017-09-14
                • 1970-01-01
                • 2021-03-28
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-02-21
                相关资源
                最近更新 更多