我想更新一个从 1 开始连续编号的表。更新有一个 where 子句,因此只有满足该子句的结果才会被重新编号。我可以在不使用临时表的情况下有效地完成此任务吗?
这可能取决于您的数据库,但这是 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
对于 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
如果您想创建新的主键列,请使用以下命令:
ALTER TABLE accounts ADD id INT IDENTITY(1,1)
为了使 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,在他的例子中是公共表表达式的名称,并且它会引发错误。
除了使用 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),连接虚拟主键列,并将要更新的列设置为生成的序列。
在 Oracle 中这是有效的:
update myTable set rowColum = rownum
where something = something else
http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/pseudocolumns009.htm#i1006297
UPDATE TableName
SET TableName.id = TableName.New_Id
FROM (
SELECT id, ROW_NUMBER() OVER (ORDER BY id) AS New_Id
FROM TableName
) TableName
我多年来一直使用这种技术来填充序数和按顺序编号的列。然而,我最近在 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。创建序列对象 - (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`
加入数字表?它涉及一个额外的表,但它不是临时的——您可以将数字表作为实用程序保留。
或
http://www.sqlservercentral.com/articles/Advanced+Querying/2547/
(后者需要免费注册,但我发现它是 MS SQL Server 技巧和技术的一个非常好的来源,并且很多内容适用于任何 SQL 实现)。
希望这个单语句解决方案能有所帮助。假设表中有一个列 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
);
SQLSERVER中的解决方案,点击进入
新查询
声明@a SMALLINT;
设置@a=0;
更新表 SET @a = 字段 = @a + 1 WHERE 不管='whatever'
它是可能的,但只能通过一些非常复杂的查询 - 基本上你需要一个子查询来计算到目前为止选择的记录数,并将其用作序列ID。我曾经写过类似的东西 - 它有效,但很痛苦。
说实话,你最好使用带有自动增量字段的临时表。