SQL Server:在行更新时为标识列重新生成值

时间:2012-08-20 03:34:59

标签: sql sql-server database-design

SequenceId是一个自动递增的标识列,但不是主键。

我想要发生的是,当更新行时,SequenceId被设置为下一个可用值,例如:

_____________________
| SequenceId | Name |
| 1          | John |
| 2          | Jane |
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

将约翰更新为杰克。 SequenceId设置为下一个可用的标识值。

_____________________
| SequenceId | Name |
| 3          | Jack |
| 2          | Jane |
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

SQL Server可以实现吗?如果没有,会有什么替代方案?

3 个答案:

答案 0 :(得分:6)

我认为你不能,至少不容易或干净。为什么不使用ROWVERSION列?每次将行更新为数据库中新的唯一递增值时,ROWVERSION列都会更新。您可以创建一个计算列,如果要对其进行索引,则将其转换为bigint。缺点是时间戳是数据库范围的,所以如果有多个表使用它们,你可以跳过数字。

FIDDLE

create table TestRowVersion (
    Id int primary key,
    Name varchar(20),
    BinaryRowVersion ROWVERSION,
    IntegerRowVersion as convert(BIGINT, BinaryRowVersion)
)   

create index IDX_TestRowVersion on TestRowVersion (IntegerRowVersion)

insert into TestRowVersion (Id, Name) values (1, 'Alvin')
insert into TestRowVersion (Id, Name) values (2, 'Betsy')
insert into TestRowVersion (Id, Name) values (3, 'Charles')
select * From TestRowVersion
update TestRowVersion set Name = 'Frank' where Id = 2
select * From TestRowVersion

[编辑] - 由于不推荐使用时间戳而更新为使用RowVersion

答案 1 :(得分:1)

  

我想要发生的是,当一行更新时,SequenceId被设置为下一个可用值......

这还不够,您还想更新序列生成器,因此下一个插入的值将是正确的。

如果您使用的是MS SQL Server 2012,则可以显式使用sequence object,而不是隐式IDENTITY。这允许您在没有INSERT的情况下生成下一个序列号,如下所示:

CREATE SEQUENCE MySquence AS INT START WITH 0;

CREATE TABLE MyTable (
    SequenceId INT DEFAULT (NEXT VALUE FOR MySquence),
    Name VARCHAR(50) PRIMARY KEY
);

INSERT INTO MyTable (Name) VALUES ('John');
INSERT INTO MyTable (Name) VALUES ('Jane');

SELECT * FROM MyTable;

    SEQUENCEID  NAME
    1           Jane
    0           John

UPDATE
    MyTable SET SequenceId = NEXT VALUE FOR MySquence,
    Name = 'Jack'
WHERE Name = 'John';

SELECT * FROM MyTable;

    SEQUENCEID  NAME
    2           Jack
    1           Jane

[SQL Fiddle]


在旧版本中,您可以通过包含单个IDENTITY列的单独表来模拟序列,然后:

  • 在该表中插入一个新行,并使用INSERT..OUTPUT(或@@IDENTITY)获取生成的自动递增数字,
  • 然后您可以立即删除该行以节省存储空间。

或者,如果您没有任何关注的参照完整性,您可以通过删除和插入来“更新”该行。

答案 2 :(得分:0)

这应该有用......

SET IDENTITY_INSERT [table] ON

UPDATE [table]
SET Name = 'some name',
    SequenceId = MAX(SequenceId) + 1
WHERE ID = 123

SET IDENTITY_INSERT [table] OFF