Scope_Identity (), Identity (), @@ Identity, และ Ident_Current () แตกต่างกันอย่างไร?


192

ฉันรู้ว่าScope_Identity(), Identity(), @@IdentityและIdent_Current()ทุกคนได้รับค่าของคอลัมน์ตัวตน แต่ฉันชอบที่จะทราบความแตกต่าง

ส่วนหนึ่งของการโต้เถียงที่ฉันมีคือพวกเขาหมายถึงอะไรตามขอบเขตที่นำไปใช้กับฟังก์ชั่นด้านบน

ฉันจะรักตัวอย่างง่ายๆของสถานการณ์ที่แตกต่างกันของการใช้พวกเขา?


2
อย่าลืมข้อผิดพลาดในการดำเนินการแบบขนานที่มีอยู่ใน SQL Server สำหรับ SCOPE_IDENTITY และ @@ IDENTITY: support.microsoft.com/default.aspx?scid=kb;en-US;2019779
David d C e Freitas

@DaviddCeFreitas - ฉันอยากรู้เกี่ยวกับข้อผิดพลาด แต่ดูเหมือนว่าลิงก์จะเสียหาย (หรืออย่างน้อยก็มีการโยนข้อผิดพลาด ASP)
rory.ap

2
จริง ๆ แล้วฉันพบว่า: support.microsoft.com/en-us/kb/2019779
rory.ap

โปรแกรมฟิกซ์ได้รับการเผยแพร่ตามที่กล่าวถึงในบทความ KB เก่านั้น
George Birbilis

คำตอบ:


396
  • @@identityฟังก์ชันส่งกลับตัวตนสุดท้ายที่สร้างขึ้นในช่วงเดียวกัน
  • scope_identity()ฟังก์ชันส่งกลับตัวตนสุดท้ายที่สร้างขึ้นในช่วงเดียวกันและขอบเขตเดียวกัน
  • ident_current(name)ผลตอบแทนที่เป็นตัวตนที่ผ่านมาที่สร้างขึ้นสำหรับตารางที่เฉพาะเจาะจงหรือมุมมองในเซสชั่นใด ๆ
  • identity()ฟังก์ชั่นที่ไม่ได้ใช้จะได้รับรหัสประจำตัวก็ใช้ในการสร้างตัวตนในselect...intoแบบสอบถาม

เซสชั่นคือการเชื่อมต่อฐานข้อมูล ขอบเขตคือแบบสอบถามปัจจุบันหรือกระบวนงานที่เก็บไว้ในปัจจุบัน

สถานการณ์ที่แตกต่างกันscope_identity()และ@@identityฟังก์ชั่นคือถ้าคุณมีทริกเกอร์บนโต๊ะ ถ้าคุณมีคิวรีที่แทรกเร็กคอร์ดทำให้ทริกเกอร์แทรกเร็กคอร์ดอื่นที่อื่นscope_identity()ฟังก์ชันจะส่งคืนข้อมูลประจำตัวที่สร้างโดยเคียวรีในขณะที่@@identityฟังก์ชันจะส่งคืนข้อมูลประจำตัวที่สร้างขึ้นโดยทริกเกอร์

ดังนั้นโดยปกติคุณจะใช้scope_identity()ฟังก์ชั่น


14
ฉันเลือกสิ่งนี้เป็นคำตอบเนื่องจาก "สถานการณ์ที่ขอบเขต scope_identity () และ @@ identity ... " ย่อหน้า มันชี้แจงสิ่งต่าง ๆ มากขึ้น
Tebo

1
ดังที่ David Freitas ได้กล่าวถึงข้างต้นมีข้อผิดพลาดในการใช้งาน scope_identity ดังนั้นฉันแนะนำให้ใช้วิธีทางเลือกคือประโยค OUTPUT ดูคำตอบของฉันด้านล่าง
เซบาสเตียนมีน

@Guffa - "เซสชันเป็นการเชื่อมต่อฐานข้อมูล" เซสชันถูกรักษาไว้ตลอดการเชื่อมต่อหรือไม่หากคุณใช้ Connection Pooling
เดฟสีดำ

1
นี่คือคำตอบแบบอย่างที่ดี โดยเฉพาะอย่างยิ่งการทำงานกับ SQL และ SQL Server นั้นแปลกและสิ่งนี้จะอธิบายสิ่งต่าง ๆ อย่างชัดเจนเป็นคนธรรมดาในขณะที่ยังคงให้ความรู้อย่างเป็นธรรม ดูเหมือนว่าจะไม่มีการสื่อสารระหว่างผู้เชี่ยวชาญด้านฐานข้อมูลสองคนซึ่ง SE ทางเลือกอื่น ๆ ก็ทำเช่นกัน
Panzercrisis

@DaveBlack จากสิ่งที่ฉันอ่าน: ไม่, เซสชั่นไม่ได้รับการบำรุงรักษาในสระว่ายน้ำ, เซสชั่นที่ไม่ซ้ำกันสำหรับการรันสคริปต์ของคุณหลังจากเชื่อมต่อ () เมื่อรวมกำไร ... PHP สำหรับ SQL Server ใช้การเชื่อมต่อ ODBC ร่วมกัน เมื่อใช้การเชื่อมต่อจากพูลสถานะการเชื่อมต่อจะถูกรีเซ็ต การปิดการเชื่อมต่อจะส่งคืนการเชื่อมต่อกับพูล (หมายเหตุ: ดูข้อสังเกตสำหรับ linux / mac) docs.microsoft.com/en-us/sql/connect/php/ …
GDmac

42

คำถามที่ดี.

  • @@IDENTITY: ส่งคืนค่าตัวตนสุดท้ายที่สร้างขึ้นในการเชื่อมต่อ SQL (SPID) เวลาส่วนใหญ่จะเป็นสิ่งที่คุณต้องการ แต่บางครั้งก็ไม่ใช่ (เช่นเมื่อมีการเรียกใช้ทริกเกอร์เพื่อตอบสนองต่อINSERTและทริกเกอร์เรียกใช้INSERTคำสั่งอื่น)

  • SCOPE_IDENTITY(): ส่งคืนค่าตัวตนสุดท้ายที่สร้างขึ้นในขอบเขตปัจจุบัน (เช่นขั้นตอนการจัดเก็บทริกเกอร์ฟังก์ชัน ฯลฯ )

  • IDENT_CURRENT(): ส่งคืนค่าเอกลักษณ์ล่าสุดสำหรับตารางที่ระบุ อย่าใช้สิ่งนี้เพื่อรับค่าตัวตนจากINSERTมันขึ้นอยู่กับสภาพการแข่งขัน (เช่นการเชื่อมต่อหลาย ๆ การแทรกแถวในตารางเดียวกัน)

  • IDENTITY(): ใช้เมื่อประกาศคอลัมน์ในตารางเป็นคอลัมน์ข้อมูลประจำตัว

สำหรับการอ้างอิงเพิ่มเติมโปรดดูที่: http://msdn.microsoft.com/en-us/library/ms187342.aspx

เพื่อสรุป: ถ้าคุณกำลังแทรกแถวและคุณต้องการที่จะรู้ค่าของคอลัมน์ประจำตัวสำหรับแถวที่คุณSCOPE_IDENTITY()เพียงแค่เสียบใช้เสมอ


16

หากคุณเข้าใจความแตกต่างระหว่างขอบเขตและเซสชันมันจะง่ายต่อการเข้าใจวิธีการเหล่านี้

โพสต์บล็อกที่ดีมากโดย Adam Anderson อธิบายความแตกต่างนี้:

เซสชันหมายถึงการเชื่อมต่อปัจจุบันที่กำลังดำเนินการคำสั่ง

ขอบเขตหมายถึงบริบททันทีของคำสั่ง การเรียกโพรซีเดอร์ที่เก็บไว้ทุกครั้งจะดำเนินการในขอบเขตของตัวเองและการโทรที่ซ้อนกันจะดำเนินการในขอบเขตที่ซ้อนภายในขอบเขตของโพรซีเดอร์การเรียก ในทำนองเดียวกันคำสั่ง SQL ที่เรียกใช้จากแอปพลิเคชันหรือ SSMS จะดำเนินการในขอบเขตของตัวเองและหากคำสั่งนั้นเรียกใช้ทริกเกอร์ใด ๆ ทริกเกอร์แต่ละตัวจะดำเนินการภายในขอบเขตที่ซ้อนกันของตัวเอง

ดังนั้นความแตกต่างระหว่างวิธีการดึงข้อมูลเฉพาะตัวทั้งสามมีดังนี้:

@@identityส่งกลับค่าตัวตนสุดท้ายที่สร้างขึ้นในเซสชั่นนี้แต่ขอบเขตใด ๆ

scope_identity()ส่งกลับค่าตัวตนสุดท้ายนี้สร้างขึ้นในครั้งนี้เซสชั่นและนี้ขอบเขต

ident_current()ส่งกลับค่าตัวตนสุดท้ายที่สร้างขึ้นสำหรับตารางโดยเฉพาะอย่างยิ่งในการใด ๆเซสชั่นและใด ๆขอบเขต


11

ขอบเขตหมายถึงบริบทรหัสที่ดำเนินการINSERTคำสั่งเมื่อเทียบกับขอบเขตทั่วโลกของSCOPE_IDENTITY()@@IDENTITY

CREATE TABLE Foo(
  ID INT IDENTITY(1,1),
  Dummy VARCHAR(100)
)

CREATE TABLE FooLog(
  ID INT IDENTITY(2,2),
  LogText VARCHAR(100)
)
go
CREATE TRIGGER InsertFoo ON Foo AFTER INSERT AS
BEGIN
  INSERT INTO FooLog (LogText) VALUES ('inserted Foo')
  INSERT INTO FooLog (LogText) SELECT Dummy FROM inserted
END

INSERT INTO Foo (Dummy) VALUES ('x')
SELECT SCOPE_IDENTITY(), @@IDENTITY 

ให้ผลลัพธ์ที่แตกต่าง


9

เนื่องจากข้อผิดพลาดที่กล่าวถึงโดย @David Freitas และเนื่องจากความไม่ลงรอยกันกับคุณลักษณะใหม่ของ Sequence ที่เปิดตัวในปี 2555 ฉันขอแนะนำให้อยู่ห่างจากทั้งสามอย่างนี้ แต่คุณสามารถใช้ส่วนคำสั่ง OUTPUT เพื่อรับค่าข้อมูลประจำตัวที่แทรก ข้อดีอีกอย่างคือ OUTPUT นั้นใช้ได้แม้คุณจะแทรกมากกว่าหนึ่งแถว

ดูรายละเอียดและตัวอย่างได้ที่นี่: Identity Crisis


ฉันคิดว่าคำตอบนี้สมควรได้รับความสนใจมากขึ้น
cheeze

ขออภัย INSERT ... OUTPUT Inserted.xx ไม่ทำงานกับทริกเกอร์ INSERT (เช่นเดียวกับ UPDATE ... OUTPUT อัปเดต. xxx และทริกเกอร์ UPDATE) พวกเขาแนะนำให้ใช้ INSERT ... OUTPUT เข้าสู่ แต่มันละเอียดเกินไปและใช้สิ่งนั้นจากไคลเอนต์ (แทนที่จะเป็น procs ที่เก็บไว้) เป็นปัญหา INSERT ... OUTPUT Inserted.xx มีความสวยงามเมื่อใช้กับการโทรฝั่งไคลเอ็นต์ (เพียงต้องการ ExecuteScalar ทำการแทรกและพูดกลับคืน id ที่สร้างอัตโนมัติสำหรับแถวใหม่) หากคุณไม่ต้องการทริกเกอร์
George Birbilis

ข้อผิดพลาดนี้ได้รับการแก้ไขแล้วหรือยัง เป็นเวลา 8 ปีแล้วที่บทความเขียนขึ้น
dopatraman

6

เพื่อชี้แจงปัญหาด้วย@@Identity:

ตัวอย่างเช่นหากคุณแทรกตารางและตารางนั้นมีทริกเกอร์ที่ทำแทรก@@Identityจะส่งคืนรหัสจากการแทรกในทริกเกอร์ ( log_idหรือบางอย่าง) ในขณะที่scope_identity()จะส่งคืน ID จากการแทรกในตารางเดิม

ดังนั้นหากคุณไม่มีทริกเกอร์ใด ๆscope_identity()และ@@identityจะคืนค่าเดิม หากคุณมีทริกเกอร์คุณต้องคิดเกี่ยวกับคุณค่าที่คุณต้องการ


4

Scope Identity: ข้อมูลประจำตัวของระเบียนล่าสุดที่เพิ่มภายในกระบวนงานที่เก็บไว้ที่จะถูกดำเนินการ

@@Identity: ข้อมูลประจำตัวของระเบียนล่าสุดที่เพิ่มภายในชุดแบบสอบถามหรือเป็นผลมาจากแบบสอบถามเช่นขั้นตอนที่ดำเนินการแทรกจากนั้นยิงทริกเกอร์ที่แทรกแล้วบันทึกจะส่งกลับตัวตนของระเบียนที่แทรกจากทริกเกอร์

IdentCurrent: ข้อมูลประจำตัวสุดท้ายที่จัดสรรสำหรับตาราง


3

นี่เป็นอีกคำอธิบายที่ดีจากหนังสือ :

สำหรับความแตกต่างระหว่าง SCOPE_IDENTITY และ @@ IDENTITY สมมติว่าคุณมีโพรซีเดอร์ที่เก็บ P1 ด้วยคำสั่งสามรายการ:
- INSERT ที่สร้างค่าเอกลักษณ์ใหม่
- การเรียกไปยังโพรซีเดอร์ที่เก็บไว้ P2 ซึ่งมีคำสั่ง INSERT ที่สร้างใหม่ ค่าเอกลักษณ์
- คำสั่งที่สอบถามฟังก์ชัน SCOPE_IDENTITY และ @@ IDENTITY ฟังก์ชัน SCOPE_IDENTITY จะส่งคืนค่าที่สร้างโดย P1 (เซสชันและขอบเขตเดียวกัน) ฟังก์ชัน @@ IDENTITY จะส่งคืนค่าที่สร้างขึ้นโดย P2 (เซสชันเดียวกันโดยไม่คำนึงถึงขอบเขต)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.