使用连续编号更新SQL

问题描述 投票:0回答:13

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

sql-server t-sql
13个回答
78
投票

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

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

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

编辑:我找到了一个利用 T-SQL for SQL Server 的解决方案。和MySQL的方法很相似:

DECLARE @myVar int
SET @myVar = 0

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

41
投票

对于 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 开始。

编辑:我刚刚注意到您似乎想在表中创建多个连续数字。根据要求,您可以使用 SQL Server 2005/2008 通过将

partition by
添加到
over
子句来一次性完成此操作:

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

5
投票

如果您想创建新的主键列,请使用以下命令:

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

4
投票

为了使 Shannon 的示例充分发挥作用,我必须编辑他的答案:

; 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,在他的例子中是公共表表达式的名称,并且它会引发错误。


4
投票

除了使用 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),连接虚拟主键列,并将要更新的列设置为生成的序列。


3
投票

在 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
投票
UPDATE TableName
SET TableName.id = TableName.New_Id
FROM (
  SELECT id, ROW_NUMBER() OVER (ORDER BY id) AS New_Id
  FROM TableName
  ) TableName

2
投票

我多年来一直使用这种技术来填充序数和按顺序编号的列。然而,我最近在 SQL Server 2012 上运行时发现了一个问题。看起来查询引擎内部正在使用多个线程应用更新,并且 UPDATE 的谓词部分没有以线程安全的方式处理。为了使其再次工作,我必须将 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

如果没有这个,您会发现整个表中大多数连续数字都是重复的。


1
投票

实现预期结果的另一种方法

1。创建序列对象 - (https://learn.microsoft.com/en-us/sql/t-sql/statements/create-sequence-transact-sql?view=sql-server-ver16)

 CREATE SEQUENCE dbo.mySeq
        AS BIGINT
        START WITH 1 -- up to you from what number you want to start cycling
        INCREMENT BY 1 -- up to you how it will increment
        MINVALUE 1
        CYCLE
        CACHE 100;

2。更新您的记录

UPDATE TableName
SET Col2 = NEXT VALUE FOR dbo.mySeq
WHERE ....some condition...

编辑:重置序列以在下次使用时从 1 开始

ALTER SEQUENCE dbo.mySeq RESTART WITH 1 -- or start with any value you need`

0
投票

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

参见 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 实现)。


0
投票

希望这个单语句解决方案能有所帮助。假设表中有一个列 id。您需要替换 table、your-integer-column 和 your-where-clause-column 占位符。

UPDATE {{table-abc}} a 
SET {{your-integer-column}} = (
  SELECT COUNT(id)+1 
  FROM {{table-abc}} 
  WHERE {{your-where-clause-column}} = {{a.your-where-clause-column}} 
  AND id > a.id 
);

0
投票

SQLSERVER中的解决方案,点击进入

新查询

声明@a SMALLINT;

设置@a=0;

更新表 SET @a = 字段 = @a + 1 WHERE 不管='whatever'


-3
投票

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

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

© www.soinside.com 2019 - 2024. All rights reserved.