这是一个执行增量的标量选择函数。
CREATE FUNCTION dbo.inc_serial( @id char(8) )
RETURNS char(8) BEGIN
select @id = case when SUBSTRING(id,2,1) <> '[' then id else STUFF( id, 1, 2, char(((ascii(id)+1-65)%26)+65) + 'A' ) end from (
select case when SUBSTRING(id,3,1) <> '[' then id else STUFF( id, 2, 2, char(ascii(right(id,7))+1) + 'A' ) end as id from (
select case when SUBSTRING(id,4,1) <> '[' then id else STUFF( id, 3, 2, char(ascii(right(id,6))+1) + 'A' ) end as id from (
select
case when right(@id,4) < '9999'
then concat( left(@id,4), right(concat( '000', (cast(right(@id,4) as smallint)+1) ), 4 ) )
else concat( left(@id,3), char(ascii(right(@id,5))+1), '0001' ) end as id
) t1 ) t2 ) t3
RETURN @id
END
基本上,代码只是在数字上加一,并重复向左溢出。
如果您的表始终只有一行要更新(例如选项/标志表):
UPDATE [table] SET [serial] = dbo.inc_serial( [serial] );
如果您的表有多行,您将需要一个标识或高精度创建时间列,以便我们知道重置后从哪里继续。
INSERT INTO [table] (serial) VALUES ( dbo.inc_serial((
select top 1 case when count(*) > 0 then max([serial]) else 'AAAA0000' end AS id
from [table] where [id] = ( select max([id]) from [table] )
)));
为了并发安全,使用 XLOCK,ROWLOCK,HOLDLOCK 来锁定表。
为简单起见,示例中省略了它们。
如果你不喜欢 udf,你可以内嵌查询。
第一种情况的内联示例:
UPDATE [table] SET [serial] = ((
select case when SUBSTRING(id,2,1) <> '[' then id else STUFF( id, 1, 2, char(((ascii(id)+1-65)%26)+65) + 'A' ) end as id from (
select case when SUBSTRING(id,3,1) <> '[' then id else STUFF( id, 2, 2, char(ascii(right(id,7))+1) + 'A' ) end as id from (
select case when SUBSTRING(id,4,1) <> '[' then id else STUFF( id, 3, 2, char(ascii(right(id,6))+1) + 'A' ) end as id from (
select
case when right(id,4) < '9999'
then concat( left(id,4), right(concat( '000', (cast(right(id,4) as smallint)+1) ), 4 ) )
else concat( left(id,3), char(ascii(right(id,5))+1), '0001' ) end as id
from (
select top 1 [serial] as id from [table] with (XLOCK,ROWLOCK,HOLDLOCK)
) t0
) t1 ) t2 ) t3
))
该函数也可以写成内联表值函数以获得更好的性能,但代价是使用更复杂,但除非它经常在多行上运行,否则我不会加边框。