知識准備
SQL Server 2005 聯機叢書
IDENTITY(屬性): 其實就是表的自增域
http://technet.microsoft.com/zh-cn/library/ms186775.ASPx
SQL Server中的 @@IDENTITY 是獲取數據表中最後一條插入數據的IDENTITY值。比如,表 A 中有個 ID 為自增1的字段,假設此時 ID 的值為100,現在如果我往表A插入一條數據,並在插入後 SELECT @@IDENTITY,則其返回 101,最後一條IDENTITY域(即ID域)的值。
現在問題來了, @@IDENTITY 它總是獲取最後一條變更數據的自增字段的值,而忽略了進行變更操作所在的范圍約束。比如,我有表 A 和表 B 兩個表,現在我在表 A 上定義了一個Insert觸發器,當在表 A 中插入一條數據時,自動在表 B 也插入一條數據。此時,大家注意,有兩個原子操作:在A中插入一條數據,接著在B中隨後插入一條數據。
現在我們想下,假設上面表 A 和表 B 都有IDENTITY自增域,那麼我們在表 A 插入一條數據後,使用了 SELECT @@IDENTITY 輸出時,輸出的到底是 A 還是 B 的自增域的值呢? 答案很明顯,是誰最後插入就輸出誰,那麼就是 B 了。於是,我本意是想得到 A 的自增域值,結果得到了 B 的自增域值,一只 BUG 隨之誕生,搞不好還會影響到整個系統數據的混亂。
對於這種情況,可以考慮使用SCOPE_IDENTITY()函數;SCOPE_IDENTITY() 也是得到最後一條自增域的值,但是它是僅限在一個操作范圍之內,SCOPE_IDENTITY ()只返回插入到當前作用域中的值,而不像 @@IDENTITY 是取全局操作的最後一步操作所產生的自增域的值的。
(注:在SQL Server中,@@identity、SCOPE_IDENTITY、IDENT_CURRENT 和 @@IDENTITY 在功能上相似,因為它們都返回插入到 IDENTITY 列中的值。 IDENT_CURRENT 不受作用域和會話的限制,而受限於指定的表。IDENT_CURRENT 返回為任何會話和作用域中的特定表所生成的值。)
看下面的例子:
USE tempdb
GO
CREATE TABLE TZ (
Z_id int IDENTITY(1,1)PRIMARY KEY,
Z_name varchar(20) NOT NULL)