【轉】SQL 2008 Insert返回自動編號id三種方法比較


SQL Server 2008中,insert數據的時候返回自動編號的id,有三種方法實現SCOPE_IDENTITY、IDENT_CURRENT 和 @@IDENTITY,

它們都返回插入到 IDENTITY 列中的值。

IDENT_CURRENT :返回為任何會話和任何作用域中的特定表最后生成的標識值。IDENT_CURRENT 不受作用域和會話的限制,而受限於指定的表。IDENT_CURRENT 返回為任何會話和作用域中的特定表所生成的值。

@@IDENTITY: 返回為當前會話的所有作用域中的任何表最后生成的標識值。

SCOPE_IDENTITY :返回為當前會話和當前作用域中的任何表最后生成的標識值

SCOPE_IDENTITY 和 @@IDENTITY 返回在當前會話中的任何表內所生成的最后一個標識值。但是,SCOPE_IDENTITY 只返回插入到當前作用域中的值;@@IDENTITY 不受限於特定的作用域。

使用示例:

set @NewID=SCOPE_IDENTITY()

set @NewID=@@IDENTITY

set @NewID=IDENT_CURRENT('表名')

例如,有兩個表 T1 和 T2,在 T1 上定義了一個 INSERT 觸發器。當將某行插入 T1 時,觸發器被激發,並在 T2 中插入一行。

此例說明了兩個作用域:一個是在 T1 上的插入,另一個是作為觸發器的結果在 T2 上的插入。

假設 T1 和 T2 都有 IDENTITY 列,@@IDENTITY 和 SCOPE_IDENTITY 將在 T1 上的 INSERT 語句的最后返回不同的值。

@@IDENTITY 返回插入到當前會話中任何作用域內的最后一個 IDENTITY 列值,該值是插入 T2 中的值。

SCOPE_IDENTITY() 返回插入 T1 中的 IDENTITY 值,該值是發生在相同作用域中的最后一個 INSERT。

如果在作用域中發生插入語句到標識列之前喚醒調用 SCOPE_IDENTITY() 函數,則該函數將返回 NULL 值。

而IDENT_CURRENT('T1') 和 IDENT_CURRENT('T2') 返回的值分別是這兩個表最后自增的值。

ajqc的實驗:(40條本地線程,40+40條遠程線程同時並發測試,插入1200W行),得出的結論是:

1.在典型的級聯應用中.不能用@@IDENTITY,在CII850,256M SD的機器上1W多行時就會並發沖突.在P42.8C,512M DDR上,才6000多行時就並發沖突.

2.SCOPE_IDENTITY()是絕對可靠的,可以用在存儲過程中,連觸發器也不用建,沒並發沖突

=================================

@@IDENTITY與SCOPE_IDENTITY() 在一條 INSERT、SELECT INTO 或大容量復制語句完成后,

@@IDENTITY 中包含語句生成的最后一個標識值。

如果語句未影響任何包含標識列的表,則 @@IDENTITY 返回 NULL。

如果插入了多個行,生成了多個標識值,則 @@IDENTITY 將返回最后生成的標識值。

如果語句觸發了一個或多個觸發器,該觸發器又執行了生成標識值的插入操作,那么,在語句執行后立即調用 @@IDENTITY 將返回觸發器生成的最后一個標識值。

如果對包含標識列的表執行插入操作后觸發了觸發器,並且觸發器對另一個沒有標識列的表執行了插入操作,則 @@IDENTITY 將返回第一次插入的標識值。

出現 INSERT 或 SELECT INTO 語句失敗或大容量復制失敗,或者事務被回滾的情況時,@@IDENTITY 值不會恢復為以前的設置。

如果語句和事務失敗,它們會更改表的當前標識,從而使標識列中的值出現不連貫現象。即使未提交試圖向表中插入值的事務,也永遠無法回滾標識值。

例如,如果因 IGNORE_DUP_KEY 沖突而導致 INSERT 語句失敗,表的當前標識值仍然會增加。 @@IDENTITY、SCOPE_IDENTITY 和 IDENT_CURRENT 是相似的函數,因為他們都返回插入到表的 IDENTITY 列的最后一個值。 @@IDENTITY 和 SCOPE_IDENTITY 可以返回當前會話中的所有表中生成的最后一個標識值。但是,SCOPE_IDENTITY 只在當前作用域內返回值,而

@@IDENTITY 不限於特定的作用域。 IDENT_CURRENT 不受作用域和會話的限制,而受限於指定的表。IDENT_CURRENT 可以返回任何會話和任何作用域中為特定表生成的標識值。 @@IDENTITY 函數的作用域是執行該函數的本地服務器上的當前會話。此函數不能應用於遠程或鏈接服務器。若要獲得其他服務器上的標識值,請在遠程服務器或鏈接服務器上執行存儲過程,並使(在遠程或鏈接服務器的環境中執行的)該存儲過程收集標識值,並將其返回本地服務器上的發出調用的連接。

以下示例向包含標識列 (LocationID) 的表中插入一行,並使用 @@IDENTITY 顯示新行中使用的標識值:

USE AdventureWorks; 
GO 
--Display the value of LocationID in the last row in the table. 
SELECT MAX(LocationID) 
FROM Production.Location; 
GO 
INSERT INTO Production.Location (Name, CostRate, Availability, ModifiedDate) 
VALUES ('Damaged Goods', 5, 2.5, GETDATE()); 
GO 
SELECT @@IDENTITY AS 'Identity';
 GO 
--Display the value of LocationID of the newly inserted row. 
SELECT MAX(LocationID) FROM Production.Location;
 GO

補充:   

我們要慎用@@IDENTITY,原因是 @@IDENTITY 它總是獲取最后一條變更數據的自增字段的值, 而忽略了進行變更操作所在的范圍約束。

比如,我有表 A 和表 B 兩個表,現在我在表 A 上定義了一個Insert觸發器,當在表 A 中插入一條數據時,自動在表 B 也插入一條數據。

此時,大家注意,有兩個原子操作:在A中插入一條數據,接着在B中隨后插入一條數據。   

現在我們想下,假設上面表 A 和表 B 都有IDENTITY自增域,那么我們在表 A 插入一條數據后,使用了 SELECT @@IDENTITY 輸出時,輸出的到底是 A 還是 B 的自增域的值呢? 答案很明顯,是誰最后插入就輸出誰,那么就是 B 了。於是,我本意是想得到 A 的自增域值,結果得到了 B 的自增域值,一只 BUG 隨之誕生,搞不好還會影響到整個系統數據的混亂。  

 因此,對於這種情況,建議大家慎用 @@IDENTITY,而盡量采用 SCOPE_IDENTITY() 函數替換之。SCOPE_IDENTITY() 也是得到最后一條自增域的值,但是它是僅限在一個操作范圍之內,而不@@IDENTITY 是取全局操作的最后一步操作所產生的自增域的值的。 ==========================

@@IDENTITY SCOPE_IDENTITY()
2008-11-05 15:02
 
   
INSERT INTO Calculation_Option (Option_Type, VIP_Option_ID, Option_Code, Option_Description, Last_Updated_Date, Last_Updated_By)
    VALUES (@Option_Type, @VIP_Option_ID, @Option_Code, @Option_Description, GetDate(), @Last_Updated_By)
SELECT @Option_ID = SCOPE_IDENTITY()

Calculation_Option這個表里面的option_Id是自動增長的,scope_identity()是為了得到自動增長后的值 這個地方用的是scope_Identity() 以下引用msdn

例如,有兩個表 T1 和 T2,並且在 T1 上定義了 INSERT 觸發器。當將某行插入 T1 時,觸發器被激發,並在 T2 中插入一行。該方案演示了兩個作用域:在 T1 上的插入,以及在 T2 通過觸發器的插入。 假設 T1 和 T2 都有標識列,@@IDENTITY 和 SCOPE_IDENTITY 將在 T1 上的 INSERT 語句的最后返回不同的值。@@IDENTITY 將返回在當前會話中的任何作用域內插入的最后一個標識列的值。這是在 T2 中插入的值。SCOPE_IDENTITY() 將返回在 T1 中插入的 IDENTITY 值。這是在同一個作用域內發生的最后的插入。如果在任何 INSERT 語句作用於作用域中的標識列之前調用 SCOPE_IDENTITY() 函數,則該函數將返回空值。

===================== 

CREATE TABLE #T(ID INT IDENTITY(1,1) PRIMARY KEY,NAME VARCHAR(20))
INSERT INTO #T SELECT 'A'
SELECT @@IDENTITY AS '@@IDENTITY',
SCOPE_IDENTITY() AS 'SCOPE_IDENTITY',
IDENT_CURRENT('#T') AS 'IDENT_CURRENT'

=====================

文章來自網絡http://zhan.renren.com/codefans?gid=3602888497997187305&from=template&checked=true


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM