已经说明(懊恼)我将为客户表创建一个主键,该主键是公司ID的组合,该公司ID是客户表中现有的varchar(4)列,例如,customer.company
varchar(9)主键的其余部分应为零填充计数器,通过该公司内的客户数量递增.
例如. company = MSFT,这是MSFT记录的第一个插入:PK应为MSFT00001
在后续插入时,PK将是MSFT00001,MSFT00002等.
然后当company = INTL并插入其第一条记录时,第一条记录将是INTL00001
我开始使用一个而不是触发器和一个我从其他stackoverflow响应创建的udf.
ALTER FUNCTION [dbo].[GetNextID] ( @in varchar(9) ) RETURNS varchar(9) AS BEGIN DECLARE @prefix varchar(9); DECLARE @res varchar(9); DECLARE @pad varchar(9); DECLARE @num int; DECLARE @start int; if LEN(@in)<9 begin set @in = Left(@in + replicate('0',9),9) end SET @start = PATINDEX('%[0-9]%',@in); SET @prefix = LEFT(@in,@start - 1 ); declare @tmp int; set @tmp = len(@in) declare @tmpvarchar varchar(9); set @tmpvarchar = RIGHT( @in,LEN(@in) - @start + 1 ) SET @num = CAST( RIGHT( @in,LEN(@in) - @start + 1 ) AS int ) + 1 SET @pad = REPLICATE( '0',9 - LEN(@prefix) - CEILING(LOG(@num)/LOG(10)) ); SET @res = @prefix + @pad + CAST( @num AS varchar); RETURN @res END
如何编写my而不是触发器来插入值并增加此主键.或者我应该放弃它并开始一个割草业务?
抱歉,没有它,tmpvarchar变量sql服务器给了我奇怪的结果.
解决方法
缺点
>仅限单排插入.您不会对新客户表进行任何批量插入,因为每次要插入行时都需要执行存储过程.
>密钥生成表存在一定程度的争用,因此存在阻塞的可能性.
但是,从好的方面来说,这种方法并没有任何与之相关的竞争条件,并且真正冒犯我的感情并不是太严重的黑客攻击.所以…
首先,从密钥生成表开始.它将包含每个公司的1行,包含您的公司标识符和每次执行插入时我们将要碰撞的整数计数器.
create table dbo.CustomerNumberGenerator ( company varchar(8) not null,curr_value int not null default(1),constraint CustomerNumberGenerator_PK primary key clustered ( company ),)
其次,你需要一个像这样的存储过程(事实上,你可能希望将这个逻辑集成到负责插入客户记录的存储过程中.稍后详细介绍).该存储过程接受公司标识符(例如“MSFT”)作为其唯一参数.此存储过程执行以下操作:
>将公司ID放入规范形式(例如,大写和修剪前导/尾随空格).
>如果该行尚不存在,则将该行插入密钥生成表(原子操作).
>在单个原子操作(更新语句)中,获取指定公司的计数器的当前值,然后递增.
>然后以指定的方式生成客户编号,并通过1行/ 1列SELECT语句返回给调用方.
干得好:
create procedure dbo.GetNewCustomerNumber @company varchar(8) as set nocount on set ansi_nulls on set concat_null_yields_null on set xact_abort on declare @customer_number varchar(32) -- -- put the supplied key in canonical form -- set @company = ltrim(rtrim(upper(@company))) -- -- if the name isn't already defined in the table,define it. -- insert dbo.CustomerNumberGenerator ( company ) select id = @company where not exists ( select * from dbo.CustomerNumberGenerator where company = @company ) -- -- now,an interlocked update to get the current value and increment the table -- update CustomerNumberGenerator set @customer_number = company + right( '00000000' + convert(varchar,curr_value),8 ),curr_value = curr_value + 1 where company = @company -- -- return the new unique value to the caller -- select customer_number = @customer_number return 0 go
您可能希望将其集成到将行插入customer表的存储过程中的原因是它将它们全部组合到一个事务中;如果没有这个,当插入失败时,您的客户编号可能会/将会出现间隙.