轉自:http://www.cnblogs.com/seusoftware/p/3804333.html
一. 獲取IDENTITY列值
插入了數據,有時還需要獲取剛才生成的序列值另作他用,返回給前端也好,或者插入其他將來需要關聯的表。
記得曾經有個面試題:假設當前表IDENTITY列最大值為N,在存儲過程中,對這個表插入1行數據,獲取到的IDENTITY列值有時小於或者大於N+1,可能是什么原因?
獲取IDENTITY列值有三種方式:
(1) IDENT_CURRENT( 'table_name' ) 返回為任何會話和任何作用域中的特定表最后生成的標識值。
(2) @@IDENTITY 返回為當前會話的所有作用域中的任何表最后生成的標識值。
(3) SCOPE_IDENTITY() 返回為當前會話和當前作用域中的任何表最后生成的標識值。
IDENT_CURRENT( 'table_name' ) 針對特定表,是全局的。@@IDENTITY和SCOPE_IDENTITY()針對所有表,區別在於作用域,也就是上下文:
(1) 如果當前INSERT語句上有函數,觸發器等(不同作用域的)對象返回的IDENTITY值,那么@@IDENTITY會取所有表上的最后1個,而不是當前表上的;
(2) SCOPE_IDENTITY()會取當前作用域所有表上最后1個IDENTITY值,被調用的函數,觸發器已經超出了作用域/上下文。所以在使用INSERT后,接着使用SCOPE_IDENTITY()獲取IDENTITY列值,就不會有問題了:
insert test values('z'); select SCOPE_IDENTITY() as curr_value
一個GO語句/批處理,也是一個上下文的分界點,但是SQL語句是順序執行的,所以一個會話里,只要在INSERT之后用SCOPE_IDENTITY()來獲取IDENTITY值是沒問題的。
二. 在IDENTITY列上做增刪改操作(DML)
(1) 刪除操作沒有問題,直接DELETE即可
delete test where id = 2
(2) 如果要顯式INSERT某個值,需要開啟IDENTITY_INSERT這個SESSION級的選項
set IDENTITY_INSERT test on; insert test(id,c1) values(3,'c'); set IDENTITY_INSERT test off; select * from test
(3) 如果要UPDATE IDENTITY列值,無論是否開啟IDENTITY_INSERT這個選項都無法更新
set IDENTITY_INSERT test on; update test set id = 10 where id = 1 set IDENTITY_INSERT test off; /* Msg 8102, Level 16, State 1, Line 1 Cannot update identity column 'id'. */
非要修改的話,就得借助中間表,在不含IDENTITY屬性的中間表里做完UPDATE,然后再把數據導回來。中間表可參考上面的腳本。