执行以下脚本,将表创建并填充到dev数据库中。
SET NOCOUNT ON
Drop Table dbo.Region
GO
CREATE TABLE dbo.Region(
RegionId int IDENTITY(1,1),
RegionName varchar(100) NOT NULL
)
GO
INSERT INTO dbo.Region (RegionName)
VALUES ('Region One'),
('Region Two');
GO
SELECT * FROM dbo.Region
这可以从一个表现良好的身份字段中得到的结果。
RegionId RegionName
----------- ------------------
1 Region One
2 Region Two
现在让我们在Identity列中强制使用几个值。
SET NOCOUNT ON
Drop Table dbo.Region
GO
CREATE TABLE dbo.Region(
RegionId int IDENTITY(1,1),
RegionName varchar(100) NOT NULL
)
GO
SET IDENTITY_INSERT dbo.Region ON;
INSERT INTO dbo.Region (RegionId, RegionName)
VALUES (-9, 'Unknown'),
(-99, 'N/A');
SET IDENTITY_INSERT dbo.Region OFF;
INSERT INTO dbo.Region (RegionName)
VALUES ('Region One'),
('Region Two');
GO
SELECT * FROM dbo.Region
输出
RegionId RegionName
----------- ------------------
-9 Unknown
-99 N/A
2 Region One
3 Region Two
RegionId = 1 去哪了?
编辑在进一步研究中,如果您尝试两次相同的特技,Sql-Server不会 跳过
SET NOCOUNT ON
Drop Table dbo.Region
GO
CREATE TABLE dbo.Region(
RegionId int IDENTITY(1,1),
RegionName varchar(100) NOT NULL
)
GO
SET IDENTITY_INSERT dbo.Region ON;
INSERT INTO dbo.Region (RegionId, RegionName)
VALUES (-9, 'Unknown'),
(-99, 'N/A');
SET IDENTITY_INSERT dbo.Region OFF;
INSERT INTO dbo.Region (RegionName)
VALUES ('Region One'),
('Region Two');
GO
SET IDENTITY_INSERT dbo.Region ON;
INSERT INTO dbo.Region (RegionId, RegionName)
VALUES (-999, 'Known-Unknown'),
(-9999, 'Really N/A');
SET IDENTITY_INSERT dbo.Region OFF;
INSERT INTO dbo.Region (RegionName)
VALUES ('Region Four'),
('Region Five');
GO
SELECT * FROM dbo.Region
这里的输出是
RegionId RegionName
----------- ------------------
-9 Unknown
-99 N/A
2 Region One
3 Region Two
-999 Known-Unknown
-9999 Really N/A
4 Region Four
5 Region Five
在之前的案例中,1
失踪了。这里4
没有丢失!
所以现在这是不可预测的遗失身份!
为什么 RegionId = 1 会丢失,但 RegionId = 4 不会丢失?!
答案 0 :(得分:6)
IDENTITY(1,1)
适用于表格中的第一行
由于您已插入两行,因此种子不再适用
当下一个身份算法检测到表中存在已有记录时,它会向种子开始添加一个,因为1可能已经被使用过。
答案 1 :(得分:3)
我也注意到了这一点,第一个身份值在某种程度上是特殊的。如果在表上执行事务,则会删除第一个标识。对于以下身份,情况并非如此。
原因似乎是current identity
以NULL
值开头:
create table YourTable (id int identity)
dbcc checkident(YourTable)
-->
Checking identity information: current identity value 'NULL',
current column value 'NULL'.
当current identity
为NULL
时,下一个要发出的号码为1
。但是任何事务,即使是不使用新身份的事务,都会导致current identity
从NULL
更改为1
:
set identity_insert YourTable on;
insert YourTable (id) values (-1)
set identity_insert YourTable off;
dbcc checkident(YourTable)
-->
Checking identity information: current identity value '1',
current column value '1'.
使用current identity
1
,下一个号码为2
:
insert YourTable default values
select * from YourTable
-->
2
因此,新表上的第一个事务对current identity
有特殊影响。它不一定是新表,它也发生在truncate table
之后。
答案 2 :(得分:1)
IDENTITY [ (seed , increment ) ]
种子
用于第一行的值是否已加载到表中。
增量
是否已添加到已加载的上一行的标识值的增量值。
因为您使用IDENTITY_INSERT
将第一行加载到表中,所以不需要该实例中的seed
。对于IDENTITY_INSERT
,还记录了
如果插入的值大于当前的标识值 在表中,SQL Server自动使用新插入的值作为 目前的身份价值。
它没有说明在您的问题中描述的情况应该发生什么,但很明显,它只是将当前的身份值设置为MAX(seed,identity_inserted)
从下面
CREATE TABLE dbo.Region(
RegionId int IDENTITY(1,1),
RegionName varchar(100) NOT NULL
)
SELECT increment_value,
last_value as last_value_new_table
FROM sys.identity_columns
WHERE name ='RegionId' AND object_id=object_id('dbo.Region')
SET IDENTITY_INSERT dbo.Region ON;
INSERT INTO dbo.Region (RegionId, RegionName)
VALUES (-9, '-9')
SET IDENTITY_INSERT dbo.Region OFF;
SELECT increment_value,
last_value as last_value_after_insert
FROM sys.identity_columns
WHERE name ='RegionId' AND object_id=object_id('dbo.Region')
DROP TABLE dbo.Region
返回
increment_value last_value_new_table
------------------------------ ------------------------------
1 NULL
increment_value last_value_after_insert
------------------------------ ------------------------------
1 1