2009-07-22 77 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),將具有要更新的列的虛擬主鍵列連接到生成的序列。