2009-07-22 72 views
26

我想更新一个以1开始的连续编号的表。更新中有一个where子句,所以只有满足子句的结果才会重新编号。我可以在不使用临时表的情况下高效完成此操作吗更新连续编号的SQL

+0

最有可能这取决于你正在运行的SQL的特定版本,我不认为有一个标准的方式来做到这一点。 – 2009-07-22 20:06:08

+0

该号码用于什么?你正在创建一个ID吗?另外,我不会担心效率低下。如果没有其他信息,这听起来不像是因为效率非常低而错过了某些东西。听起来像是一次性的操作。 – 2009-07-22 20:10:23

+0

我每周在2GB管道分隔文件中获得150万条清单。我需要运行一个存储过程来确定哪些列表位于我的客户端城市,并为其提供客户端ID,并为每个客户端顺序编号。它必须是高效的。 – Bryan 2009-07-22 20:14:40

回答

41

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

SET @a:=0; 
UPDATE table SET [email protected]:[email protected]+1 WHERE whatever='whatever' ORDER BY field2,field3 

你或许应该修改你的问题,但是表明你正在使用的数据库。

编辑:我发现一个solution利用SQL Server的T-SQL。这非常类似于MySQL的方法:

DECLARE @myVar int 
SET @myVar = 0 

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

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

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

23

对于Microsoft SQL Server 2005/2008。在2005年

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

编辑加入ROW_NUMBER()函数:对于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 byover条款:

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

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

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

我已经使用这种技术多年来填充顺序和顺序编号的列。不过,我最近在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 

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

0

要由香完全工作,我不得不修改他的回答得到的例子:

; 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,这对他来说是公用表表达式的名称,它抛出一个错误。

0

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