标识列未生成正确的ID

时间:2014-02-01 19:45:30

标签: sql sql-server sql-server-2012

我有一张桌子:

CREATE TABLE [dorkOrder] ( 
    [doId] int identity(1,1)  NOT NULL,
    [shId] int NOT NULL,
    [mopId] int NOT NULL,
    [dorkOrderNo] varchar(20) NULL,
    [doDate] date NULL
);

现在当我向其中插入数据而不是以这种方式doId生成1,2,3,4,5,6,7时,它会以下面的奇怪方式生成数据:

1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
2002
2003
2004
2005
2006
2007
2008
2013

请帮我解决这个问题。

2 个答案:

答案 0 :(得分:5)

这是known issue in SQL Server 2012。但即使没有这个错误(可能会在某一天修复,但可能不会修复),您应该期望您的IDENTITY列可能存在空白。这些可能由于各种原因而发生,包括删除和回滚。

如果要实现没有间隙的顺序列,则停止使用IDENTITY,在插入新行的基础上构建强大的可序列化进程,并拒绝对该表上的所有人执行删除/截断。

否则,由于微软表示他们已经absolutely no intention of offering a "gapless sequential" feature,所以要学会忍受差距。

答案 1 :(得分:0)

这是一个小小的测试脚本,向您展示有关标识列的一些有趣的事情

1 - 大多数人使用(1,1)。

然而,您可以使用(1,5)增加5,这将留下空白 如果你愿意,也可以从(2000,1)两千开始。

2 - 删除表中的所有记录不会重置计数器。

3 - 截断表格会将计数器重置为基数。

4 - 差距可能是由于删除或阻止插入的条件造成的。

示例触发器最后显示是否没有播放大笔资金,会出现差距。

5 - 最后但并非最不重要的是,你可以从一个类型的负范围开始。

对于INT,从-2147483648开始向2147483647递增,给出两倍的数字。 但是,如果用户看到id,您可能不希望这样。然后使用BIGINT。

-- Just playing
use tempdb;
go

-- drop existing
if object_id('superbowl_pool') > 0
drop table superbowl_pool
go


-- create new
create table superbowl_pool
(
id int identity (1,1) primary key,
cash smallmoney
);

-- add data
declare @a int = 0;
while (@a < 100)
begin
  insert into superbowl_pool (cash) values (rand(checksum(newid())) * 50);
  set @a += 1;
end
go

-- show the data
select * from superbowl_pool;

显示删除的用户不要重置计数器。

-- delete does not reset the counter
delete from superbowl_pool;
go

-- Two records
insert into superbowl_pool (cash) values (rand(checksum(newid())) * 50);
insert into superbowl_pool (cash) values (rand(checksum(newid())) * 50);
go

-- Gaps in id column
delete from superbowl_pool where id = 102;
insert into superbowl_pool (cash) values (rand(checksum(newid())) * 50);

-- show the data
select * from superbowl_pool;

向用户显示截断重置计数器。

-- truncate table
truncate table superbowl_pool;

-- Two records
insert into superbowl_pool (cash) values (rand(checksum(newid())) * 50);
insert into superbowl_pool (cash) values (rand(checksum(newid())) * 50);
go

-- show the data
select * from superbowl_pool;

用户必须玩20美元或更多

-- create ins trigger
create trigger dbo.trg_big_money on dbo.superbowl_pool
FOR INSERT
AS
BEGIN

  IF EXISTS (SELECT * FROM inserted where cash < 20)
      ROLLBACK;
END