2011-06-16 15 views
6

執行以下腳本,該腳本可以創建表並將其填充到開發數據庫中。行爲不端身份

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 

現在讓我們強制一些值進入標識列。

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的服務器不跳過什麼,如果你嘗試同樣的特技兩次

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沒有失蹤?

+1

這是純粹的研究還是你真的需要1?我問,因爲普遍的共識是,如果你使用IDENTITY/AUTONUMBER,你會說「我實際上並不關心*實際*值是什麼,只要它是唯一的」。也就是說,你*要關心價值是什麼,但不足以確保它是一個特定的價值,你只需讓數據庫決定。 – 2011-06-16 19:59:22

+0

我很確定我明白代理鍵是什麼以及如何使用標識字段。我不需要'1'。然而,正如你從我的兩個例子中無疑可以看出的那樣,這個例子變成了一個特例。我確實想知道它去了哪裏以及爲什麼。 – 2011-06-16 20:02:45

+0

我同意,這是一個非常好的和有趣的問題! – 2011-06-16 20:04:17

回答

6

IDENTITY(1,1)適用於第一行中的表

既然你已經有兩行插入種子不再適用

下一個標識算法將一個種子開始,當它檢測到存在自1開始,表中現有的記錄可能已被使用。

+0

但是吉博,我沒有碰到種子 - 我插入了我自己的身份! – 2011-06-16 20:05:09

+2

1的種子只適用於FIRST記錄,通過在種子可以使用之前添加自己的記錄而間接影響它 - 下一個身份算法知道存在現有記錄,因此從第一個種子開始可能毫無意義 - 所以無論正確還是錯誤,它都會開始尋找種子+1來獲得下一個可用的身份。 – Jimbo 2011-06-16 20:13:28

+1

@Raj更多:你甚至可以在插入其他行之前刪除你的第一行*,而最後一行的標識列的值爲2.我的意思是,你插入了從未使用過標識1的行,然後刪除它們,這仍然會阻止你自動獲得身份1。 – 2011-06-18 14:21:30

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 identityNULL,下一個數字被賦予了是1。但是,任何交易,甚至是一個不消耗一個新的身份,使current identity改變從NULL1

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'. 

隨着1current identity,下一個數字將是2

insert YourTable default values 
select * from YourTable 
--> 
2 

因此,新鮮餐桌上的第一筆交易對current identity有特殊效果。它不一定是新表,它也發生在truncate table之後。

1

SQL Server Books Online

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