วิธีที่ดีที่สุดในการรับข้อมูลประจำตัวของแถวที่แทรก?


1119

วิธีที่ดีที่สุดในการIDENTITYแทรกแถวคืออะไร

ฉันรู้เกี่ยวกับ@@IDENTITYและIDENT_CURRENTและSCOPE_IDENTITYแต่ไม่เข้าใจข้อดีข้อเสียของแต่ละข้อ

ใครช่วยอธิบายความแตกต่างได้และเมื่อใดควรใช้แต่ละข้อ


5
INSERT INTO Table1(fields...) OUTPUT INSERTED.id VALUES (...)หรือวิธีที่เก่ากว่า: INSERT INTO Table1(fields...) VALUES (...); SELECT SCOPE_IDENTITY();คุณสามารถรับมันใน c # โดยใช้ ExecuteScalar ()
S.Serpooshan

4
ดีกว่าคำตอบอื่น ๆ อย่างไร (เช่น - ทำไมคุณไม่โพสต์สิ่งนี้เป็นคำตอบแทนความคิดเห็น) โปรดเขียนคำตอบที่สมบูรณ์ (และอธิบายว่าทำไมนี่จึงเป็นตัวเลือกที่ดีกว่าคำตอบที่โพสต์ - ถ้าเฉพาะเวอร์ชั่นให้พูดอย่างนั้น)
Oded

มันเป็นเหมือนบทสรุปสั้น ๆ ; D คำตอบที่ยอมรับไม่ได้กล่าวถึงไวยากรณ์ของคำสั่งย่อย OUTPUT และไม่มีตัวอย่าง นอกจากนี้ยังมีตัวอย่างในกระทู้อื่น ๆ ที่ไม่สะอาดดังนั้น ...
S.Serpooshan

2
@saeedserpooshan - จากนั้นแก้ไขในสิ่งต่อไปนี้คุณสามารถทำได้ใช่ไหม เห็นเมื่อคำตอบนั้นถูกโพสต์? ที่มาก่อนส่วนOUTPUTคำสั่งใน SQL Server
Oded

คำตอบ:


1434
  • @@IDENTITYส่งคืนค่าเอกลักษณ์ล่าสุดที่สร้างขึ้นสำหรับตารางใด ๆ ในเซสชันปัจจุบันข้ามขอบเขตทั้งหมด คุณต้องระวังที่นี่เนื่องจากมันข้ามขอบเขต คุณสามารถรับค่าจากทริกเกอร์แทนที่จะเป็นคำสั่งปัจจุบันของคุณ

  • SCOPE_IDENTITY()ส่งคืนค่าเอกลักษณ์ล่าสุดที่สร้างขึ้นสำหรับตารางใด ๆ ในเซสชันปัจจุบันและขอบเขตปัจจุบัน โดยทั่วไปสิ่งที่คุณต้องการใช้

  • IDENT_CURRENT('tableName')ส่งคืนค่าเอกลักษณ์ล่าสุดที่สร้างขึ้นสำหรับตารางที่ระบุในเซสชันใด ๆ และขอบเขตใด ๆ สิ่งนี้ช่วยให้คุณระบุตารางที่คุณต้องการค่าในกรณีที่ทั้งสองข้างต้นไม่ได้เป็นสิ่งที่คุณต้องการ ( หายากมาก ) นอกจากนี้ตามที่ @ Guy Starbuckพูดถึง "คุณสามารถใช้สิ่งนี้หากคุณต้องการรับค่าตัวตนปัจจุบันสำหรับตารางที่คุณไม่ได้แทรกบันทึกลงไป"

  • OUTPUTประโยคของINSERTคำสั่งที่จะช่วยให้คุณเข้าถึงแถวที่ถูกแทรกผ่านคำสั่งที่ทุก เนื่องจากมันถูกกำหนดขอบเขตให้กับคำสั่งเฉพาะจึงตรงไปตรงมามากกว่าฟังก์ชั่นอื่น ๆ ด้านบน อย่างไรก็ตามมันเป็นverbose อีกเล็กน้อย(คุณจะต้องแทรกลงในตัวแปร table / temp table แล้วทำการค้นหา) และให้ผลลัพธ์แม้ในสถานการณ์ข้อผิดพลาดที่คำสั่งถูกย้อนกลับ ที่กล่าวว่าหากแบบสอบถามของคุณใช้แผนการดำเนินการแบบขนานนี่เป็นวิธีเดียวที่รับประกันการรับข้อมูลประจำตัว (ย่อมาจากการปิดแบบขนาน) อย่างไรก็ตามมันจะถูกดำเนินการก่อนทริกเกอร์และไม่สามารถใช้เพื่อส่งกลับค่าที่สร้างทริกเกอร์


48
ข้อผิดพลาดที่รู้จักกับ SCOPE_IDENTITY () ส่งคืนค่าที่ไม่ถูกต้อง: blog.sqlauthority.com/2009/03/24/…การแก้ไขคือไม่ใช้ INSERT ใน Multi Processor Parallel Plan หรือใช้ส่วนคำสั่ง OUTPUT
KM

3
เกือบทุกครั้งที่ฉันต้องการ 'ตัวตน' ฉันต้องการทราบถึงกุญแจของบันทึกที่ฉันใส่เข้าไป หากนั่นคือสถานการณ์ของคุณคุณต้องการใช้ส่วนคำสั่งเอาท์พุท หากคุณต้องการอย่างอื่นใช้ความพยายามในการอ่านและทำความเข้าใจการตอบสนอง bdukes
jerry

3
ด้วยoutputคุณไม่จำเป็นต้องสร้างตารางชั่วคราวเพื่อจัดเก็บและค้นหาผลลัพธ์ เพียงแค่ละทิ้งintoส่วนหนึ่งของส่วนคำสั่งเอาท์พุทและมันจะเอาท์พุทไปยังชุดผลลัพธ์
spb

96
ในการบันทึกผู้อื่นจากการตื่นตระหนกข้อผิดพลาดที่กล่าวถึงข้างต้นได้รับการแก้ไขใน Cumulative Update 5 สำหรับ SQL Server 2008 R2 Service Pack 1
GaTechThomas

1
@ Niico ฉันคิดว่าคำแนะนำเหมือนเดิมซึ่งก็OUTPUTคือ "ดีที่สุด" ตราบใดที่คุณไม่ได้ใช้ทริกเกอร์และจัดการข้อผิดพลาด แต่SCOPE_IDENTITYเป็นปัญหาที่ง่ายที่สุดและไม่ค่อยเกิดขึ้น
bdukes

180

ฉันเชื่อว่าวิธีที่ปลอดภัยและแม่นยำที่สุดในการเรียกรหัสที่แทรกไว้จะเป็นการใช้ส่วนคำสั่งเอาท์พุท

ตัวอย่าง (นำมาจากบทความMSDNต่อไปนี้)

USE AdventureWorks2008R2;
GO
DECLARE @MyTableVar table( NewScrapReasonID smallint,
                           Name varchar(50),
                           ModifiedDate datetime);
INSERT Production.ScrapReason
    OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
        INTO @MyTableVar
VALUES (N'Operator error', GETDATE());

--Display the result set of the table variable.
SELECT NewScrapReasonID, Name, ModifiedDate FROM @MyTableVar;
--Display the result set of the table.
SELECT ScrapReasonID, Name, ModifiedDate 
FROM Production.ScrapReason;
GO

3
ใช่นี่เป็นวิธีที่ถูกต้องในการก้าวไปข้างหน้าใช้หนึ่งในวิธีอื่นถ้าคุณไม่ได้อยู่ใน SQL Server 2008 (เราข้าม 2005 ดังนั้นไม่แน่ใจว่าถ้า OUTPUT พร้อมใช้งานแล้ว)
HLGEM

1
@HLGEM มีหน้า MSDN สำหรับOUTPUTใน SQL Server 2005ดังนั้นดูเหมือนว่าเป็นเพียง SQL Server 2000 และรุ่นก่อนหน้านี้ที่ไม่มี
bdukes

6
woohoo! เอาท์พุทปะทะหิน :) นั่นจะทำให้งานปัจจุบันของฉันง่ายขึ้น ไม่เคยรู้มาก่อนเลย ขอบคุณทุกคน!
SwissCoder

8
สำหรับตัวอย่างที่กระชับจริงๆที่เพิ่งได้รับ ID ที่แทรกให้ดูที่: stackoverflow.com/a/10999467/2003325
ลุค

การใช้ INTO กับ OUTPUT ของคุณเป็นความคิดที่ดี ดู: blogs.msdn.microsoft.com/sqlprogrammability/2008/07/11/… (จากความคิดเห็นที่นี่: stackoverflow.com/questions/7917695/… )
shlgug

112

ฉันกำลังพูดในสิ่งเดียวกันกับคนอื่นดังนั้นทุกคนถูกต้องฉันแค่พยายามทำให้ชัดเจนยิ่งขึ้น

@@IDENTITYส่งคืน id ของสิ่งสุดท้ายที่ถูกแทรกโดยการเชื่อมต่อของลูกค้าของคุณไปยังฐานข้อมูล
เวลาส่วนใหญ่ใช้งานได้ดี แต่บางครั้งทริกเกอร์จะไปและแทรกแถวใหม่ที่คุณไม่รู้จักและคุณจะได้รับ ID จากแถวใหม่นี้แทนที่จะเป็นแถวที่คุณต้องการ

SCOPE_IDENTITY()แก้ปัญหานี้ มันคืนค่า id ของสิ่งสุดท้ายที่คุณใส่ในรหัส SQL ที่คุณส่งไปยังฐานข้อมูล หากทริกเกอร์ไปและสร้างแถวเพิ่มเติมพวกเขาจะไม่ทำให้ค่าผิดกลับคืนมา ไชโย

IDENT_CURRENTส่งคืน ID ล่าสุดที่ถูกแทรกโดยทุกคน หากมีแอปอื่นแทรกแถวอื่นในเวลาที่ไม่คาดคิดคุณจะได้รับ ID ของแถวนั้นแทนแอพของคุณ

SCOPE_IDENTITY()ถ้าคุณต้องการที่จะเล่นที่ปลอดภัยใช้เสมอ หากคุณติดกับ@@IDENTITYใครบางคนตัดสินใจที่จะเพิ่มทริกเกอร์ในภายหลังรหัสของคุณทั้งหมดจะแตก


64

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

create table TableWithIdentity
           ( IdentityColumnName int identity(1, 1) not null primary key,
             ... )

-- type of this table's column must match the type of the
-- identity column of the table you'll be inserting into
declare @IdentityOutput table ( ID int )

insert TableWithIdentity
     ( ... )
output inserted.IdentityColumnName into @IdentityOutput
values
     ( ... )

select @IdentityValue = (select ID from @IdentityOutput)

5
การทำคลัสเตอร์เซิร์ฟเวอร์ SQL เป็นคุณสมบัติที่มีความพร้อมใช้งานสูงและไม่มีผลกระทบต่อการขนาน เป็นเรื่องแปลกมากสำหรับเม็ดมีดแถวเดี่ยว (กรณีที่พบบ่อยที่สุดสำหรับscope_identity()) ในการรับแผนคู่ขนาน และข้อผิดพลาดนี้ได้รับการแก้ไขมากกว่าหนึ่งปีก่อนคำตอบนี้
Martin Smith

คุณหมายถึงอะไรโดยการขนาน
user1451111

@MartinSmith ลูกค้าไม่เต็มใจที่จะช่วยให้การหยุดทำงานบนเซิร์ฟเวอร์คลัสเตอร์ของพวกเขาในการติดตั้งจุฬาฯ แก้ไขปัญหานี้ (ไม่ได้ล้อเล่น) ดังนั้นวิธีการแก้ปัญหาอย่างเดียวคือสำหรับเราที่จะเขียนทั้งหมด SQL เพื่อใช้แทนoutput scope_identity()ฉันลบ FUD เกี่ยวกับการรวมกลุ่มในคำตอบ
Ian Kemp

1
ขอบคุณนี่เป็นเพียงตัวอย่างเดียวที่ฉันสามารถค้นหาได้ซึ่งแสดงวิธีใช้ค่าจากผลลัพธ์ในตัวแปรแทนที่จะแสดงผลลัพธ์
Sean Ray

26

เพิ่ม

SELECT CAST(scope_identity() AS int);

ที่ส่วนท้ายของคำสั่งแทรก sql ของคุณจากนั้น

NewId = command.ExecuteScalar()

จะดึงมันมา


18

เมื่อคุณใช้ Entity Framework ภายในจะใช้OUTPUTเทคนิคเพื่อส่งคืนค่า ID ที่แทรกใหม่

DECLARE @generated_keys table([Id] uniqueidentifier)

INSERT INTO TurboEncabulators(StatorSlots)
OUTPUT inserted.TurboEncabulatorID INTO @generated_keys
VALUES('Malleable logarithmic casing');

SELECT t.[TurboEncabulatorID ]
FROM @generated_keys AS g 
   JOIN dbo.TurboEncabulators AS t 
   ON g.Id = t.TurboEncabulatorID 
WHERE @@ROWCOUNT > 0

ผลลัพธ์ของผลลัพธ์จะถูกเก็บไว้ในตัวแปรตารางชั่วคราวเข้าร่วมกลับไปที่ตารางและส่งกลับค่าแถวออกจากตาราง

หมายเหตุ: ฉันไม่รู้ว่าทำไม EF จะเข้าร่วมตารางชั่วคราวกลับไปที่ตารางจริง (ทั้งสองสถานการณ์จะไม่ตรงกัน)

แต่นั่นคือสิ่งที่ EF ทำ

เทคนิคนี้ ( OUTPUT) มีเฉพาะใน SQL Server 2008 หรือใหม่กว่าเท่านั้น

แก้ไข - เหตุผลในการเข้าร่วม

เหตุผลที่ Entity Framework เชื่อมโยงกลับไปที่ตารางดั้งเดิมแทนที่จะใช้OUTPUTค่าเพียงเพราะ EF ยังใช้เทคนิคนี้เพื่อรับrowversionแถวที่แทรกใหม่

คุณสามารถใช้การเห็นพ้องในแง่ดีในโมเดลเอนทิตี้ของเฟรมเวิร์กโดยใช้แอTimestampททริบิว: 🕗

public class TurboEncabulator
{
   public String StatorSlots)

   [Timestamp]
   public byte[] RowVersion { get; set; }
}

เมื่อคุณทำเช่นนี้ Entity Framework จะต้องการrowversionแถวที่แทรกใหม่:

DECLARE @generated_keys table([Id] uniqueidentifier)

INSERT INTO TurboEncabulators(StatorSlots)
OUTPUT inserted.TurboEncabulatorID INTO @generated_keys
VALUES('Malleable logarithmic casing');

SELECT t.[TurboEncabulatorID], t.[RowVersion]
FROM @generated_keys AS g 
   JOIN dbo.TurboEncabulators AS t 
   ON g.Id = t.TurboEncabulatorID 
WHERE @@ROWCOUNT > 0

และเพื่อที่จะดึงข้อมูลนี้Timetsampคุณไม่สามารถใช้ส่วนOUTPUTคำสั่งได้

นั่นเป็นเพราะหากมีการเรียกบนโต๊ะใด ๆ ที่Timestampคุณส่งออกจะผิด:

  • เริ่มต้นแทรก เวลาประทับ: 1
  • ข้อ OUTPUT เอาท์พุทประทับเวลา: 1
  • ทริกเกอร์แก้ไขแถว เวลาประทับ: 2

การประทับเวลาที่ส่งคืนจะไม่ถูกต้องหากคุณมีทริกเกอร์บนตาราง ดังนั้นคุณจะต้องSELECTใช้แยกต่างหาก

และแม้ว่าคุณจะยินดีที่จะได้รับความถูกต้อง rowversion เหตุผลอื่นในการดำเนินการแยกต่างหากSELECTคือคุณไม่สามารถส่งrowversionออกเป็นตัวแปรตาราง:

DECLARE @generated_keys table([Id] uniqueidentifier, [Rowversion] timestamp)

INSERT INTO TurboEncabulators(StatorSlots)
OUTPUT inserted.TurboEncabulatorID, inserted.Rowversion INTO @generated_keys
VALUES('Malleable logarithmic casing');

เหตุผลที่สามที่ต้องทำเพื่อความสมมาตร เมื่อทำการแสดงUPDATEบนโต๊ะที่มีทริกเกอร์คุณจะไม่สามารถใช้OUTPUTประโยคได้ การลองทำUPDATEด้วย an OUTPUTไม่ได้รับการสนับสนุนและจะให้ข้อผิดพลาด:

วิธีเดียวที่จะทำได้คือใช้SELECTคำสั่งติดตามผล:

UPDATE TurboEncabulators
SET StatorSlots = 'Lotus-O deltoid type'
WHERE ((TurboEncabulatorID = 1) AND (RowVersion = 792))

SELECT RowVersion
FROM TurboEncabulators
WHERE @@ROWCOUNT > 0 AND TurboEncabulatorID = 1

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

16

MSDN

@@ IDENTITY, SCOPE_IDENTITY และ IDENT_CURRENT เป็นฟังก์ชั่นที่คล้ายกันซึ่งจะส่งคืนค่าสุดท้ายที่แทรกเข้าไปในคอลัมน์ IDENTITY ของตาราง

@@ IDENTITY และ SCOPE_IDENTITY จะส่งกลับค่าตัวตนสุดท้ายที่สร้างในตารางใด ๆ ในเซสชันปัจจุบัน อย่างไรก็ตาม SCOPE_IDENTITY ส่งคืนค่าภายในขอบเขตปัจจุบันเท่านั้น @@ IDENTITY ไม่ จำกัด เฉพาะขอบเขต

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

  • IDENT_CURRENTเป็นฟังก์ชันที่ใช้ตารางเป็นอาร์กิวเมนต์
  • @@ IDENTITYอาจส่งคืนผลลัพธ์ที่สับสนเมื่อคุณมีทริกเกอร์บนโต๊ะ
  • SCOPE_IDENTITYเป็นฮีโร่ของคุณเกือบตลอดเวลา

14

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

SCOPE_IDENTITYเป็นข้อมูลประจำตัวสุดท้ายที่แทรกโดยใช้การเชื่อมต่อ SQL ปัจจุบันและในขอบเขตปัจจุบัน - นั่นคือถ้ามีการระบุตัวตนที่สองขึ้นอยู่กับทริกเกอร์หลังจากแทรกของคุณมันจะไม่ปรากฏใน SCOPE_IDENTITY เฉพาะแทรกที่คุณดำเนินการ . ตรงไปตรงมาฉันไม่เคยมีเหตุผลที่จะใช้สิ่งนี้

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


2
คุณไม่ควรใช้ @@ ข้อมูลประจำตัวเพื่อจุดประสงค์นี้ หากมีคนเพิ่มทริกเกอร์ในภายหลังคุณจะสูญเสียความถูกต้องของข้อมูล @@ identiy เป็นการปฏิบัติที่อันตรายอย่างยิ่ง
HLGEM

1
"ค่าสำหรับตารางที่คุณ <<not>> แทรกระเบียนไว้" จริงๆ?
Abdul Saboor

13

ฉันไม่สามารถพูดคุยกับ SQL Server รุ่นอื่น ๆ ได้ แต่ในปี 2012 การแสดงผลออกมาใช้งานได้ดี คุณไม่จำเป็นต้องกังวลกับตารางชั่วคราว

INSERT INTO MyTable
OUTPUT INSERTED.ID
VALUES (...)

โดยวิธีการเทคนิคนี้ยังใช้งานได้เมื่อแทรกหลายแถว

INSERT INTO MyTable
OUTPUT INSERTED.ID
VALUES
    (...),
    (...),
    (...)

เอาท์พุต

ID
2
3
4

หากคุณต้องการใช้ในภายหลังแม้ว่าฉันคิดว่าคุณต้องการตารางอุณหภูมิ
JohnOsborne

@JohnOsborne คุณจะยินดีที่จะใช้ตาราง temp ถ้าคุณต้องการ OUTPUTแต่จุดของฉันก็คือว่ามันไม่ได้เป็นความต้องการของ หากคุณไม่ต้องการตาราง temp การค้นหาของคุณจะจบลงง่ายกว่าเดิม
MarredCheese

10

ใช้ scope_identity () เสมอไม่จำเป็นต้องมีสิ่งใดเลย


13
ไม่มากไม่เคยแต่ครั้งที่ 99 จาก 100 คุณจะใช้ SCOPE_IDENTITY ()
CJM

สำหรับสิ่งที่คุณเคยใช้อะไรอย่างอื่น?
erikkallen

11
หากคุณแทรกหลายแถวด้วย INSERT-SELECT คุณจะต้องจับภาพหลาย ID โดยใช้คำสั่ง OUTPUT
KM

1
@KM: ใช่ แต่ฉันอ้างถึง scope_identity vs @@ identity vs ident_current เอาท์พุทเป็นคลาสที่แตกต่างอย่างสิ้นเชิงและมักจะมีประโยชน์
erikkallen

2
ลองดูคำตอบ( stackoverflow.com/a/6073578/2440976 ) ของ Orry สำหรับคำถามนี้ - ในแบบคู่ขนานและเป็นแนวปฏิบัติที่ดีที่สุดคุณควรทำตามการตั้งค่าของเขา ... ยอดเยี่ยม!
Dan B

2

สร้างuuidและยังแทรกลงในคอลัมน์ จากนั้นคุณสามารถระบุแถวของคุณได้อย่างง่ายดายด้วย uuid นั่นเป็นโซลูชั่นการทำงานเพียง 100% ที่คุณสามารถนำไปใช้ได้ โซลูชันอื่นทั้งหมดนั้นซับซ้อนเกินไปหรือใช้งานไม่ได้ในกรณีขอบเดียวกัน เช่น:

1) สร้างแถว

INSERT INTO table (uuid, name, street, zip) 
        VALUES ('2f802845-447b-4caa-8783-2086a0a8d437', 'Peter', 'Mainstreet 7', '88888');

2) สร้างแถว

SELECT * FROM table WHERE uuid='2f802845-447b-4caa-8783-2086a0a8d437';

อย่าลืมสร้างดัชนีสำหรับuuidในฐานข้อมูล ดังนั้นแถวจะพบได้เร็วขึ้น
Frank Roth

สำหรับ Node.js คุณสามารถใช้โมดูลนี้จะเพียงแค่สร้าง uuid https://www.npmjs.com/package/uuidนี้: const uuidv4 = require('uuid/v4'); const uuid = uuidv4()
Frank Roth

GUID ไม่ใช่ค่าตัวตน แต่ก็มีการแบ็คอัพบางอย่างเมื่อเทียบกับจำนวนเต็มแบบง่าย
Alejandro

1

อีกวิธีหนึ่งที่จะรับประกันตัวตนของแถวที่คุณแทรกคือการระบุค่าตัวตนและใช้แล้วSET IDENTITY_INSERT ON OFFสิ่งนี้รับประกันว่าคุณจะรู้ว่าคุณค่าของตัวตนคืออะไร! ตราบใดที่ค่าไม่ได้ใช้งานคุณสามารถแทรกค่าเหล่านี้ลงในคอลัมน์ข้อมูลประจำตัว

CREATE TABLE #foo 
  ( 
     fooid   INT IDENTITY NOT NULL, 
     fooname VARCHAR(20) 
  ) 

SELECT @@Identity            AS [@@Identity], 
       Scope_identity()      AS [SCOPE_IDENTITY()], 
       Ident_current('#Foo') AS [IDENT_CURRENT] 

SET IDENTITY_INSERT #foo ON 

INSERT INTO #foo 
            (fooid, 
             fooname) 
VALUES      (1, 
             'one'), 
            (2, 
             'Two') 

SET IDENTITY_INSERT #foo OFF 

SELECT @@Identity            AS [@@Identity], 
       Scope_identity()      AS [SCOPE_IDENTITY()], 
       Ident_current('#Foo') AS [IDENT_CURRENT] 

INSERT INTO #foo 
            (fooname) 
VALUES      ('Three') 

SELECT @@Identity            AS [@@Identity], 
       Scope_identity()      AS [SCOPE_IDENTITY()], 
       Ident_current('#Foo') AS [IDENT_CURRENT] 

-- YOU CAN INSERT  
SET IDENTITY_INSERT #foo ON 

INSERT INTO #foo 
            (fooid, 
             fooname) 
VALUES      (10, 
             'Ten'), 
            (11, 
             'Eleven') 

SET IDENTITY_INSERT #foo OFF 

SELECT @@Identity            AS [@@Identity], 
       Scope_identity()      AS [SCOPE_IDENTITY()], 
       Ident_current('#Foo') AS [IDENT_CURRENT] 

SELECT * 
FROM   #foo 

นี่เป็นเทคนิคที่มีประโยชน์มากถ้าคุณกำลังโหลดข้อมูลจากแหล่งอื่นหรือรวมข้อมูลจากฐานข้อมูลสองแห่งเป็นต้น


0

แม้จะเป็นหัวข้อเก่ามีวิธีใหม่ที่จะทำนี้ที่หลีกเลี่ยงบางส่วนของข้อผิดพลาดของรหัสประจำตัวคอลัมน์ในรุ่นเก่าของ SQL Server, เช่นช่องว่างในค่าตัวตนหลังจากรีบูตเซิร์ฟเวอร์ ลำดับที่มีอยู่ใน SQL Server 2016 และส่งต่อซึ่งเป็นวิธีที่ใหม่กว่าคือการสร้างวัตถุลำดับโดยใช้ TSQL สิ่งนี้ช่วยให้คุณสร้างวัตถุลำดับตัวเลขของคุณเองใน SQL Server และควบคุมวิธีการเพิ่มขึ้น

นี่คือตัวอย่าง:

CREATE SEQUENCE CountBy1  
    START WITH 1  
    INCREMENT BY 1 ;  
GO  

จากนั้นใน TSQL คุณจะทำสิ่งต่อไปนี้เพื่อรับ ID ลำดับถัดไป:

SELECT NEXT VALUE FOR CountBy1 AS SequenceID
GO

นี่คือลิงค์สำหรับสร้างลำดับและมูลค่าถัดไปสำหรับ


ลำดับมีปัญหาเดียวกันเกี่ยวกับตัวตนเช่นช่องว่าง (ซึ่งไม่ใช่ปัญหาจริงๆ)
Alejandro

-1

หลังจากคำสั่งแทรกของคุณคุณจะต้องเพิ่มนี้ และตรวจสอบให้แน่ใจเกี่ยวกับชื่อตารางที่มีการแทรกข้อมูลคุณจะได้รับแถวปัจจุบันไม่มีตำแหน่งที่ได้รับผลกระทบจากคำสั่งแทรกของคุณ

IDENT_CURRENT('tableName')

2
คุณสังเกตเห็นว่าคำแนะนำเดียวกันนี้ได้รับคำตอบมาหลายครั้งแล้วหรือไม่
TT

ใช่. แต่ฉันพยายามอธิบายวิธีการแก้ปัญหาด้วยวิธีของฉันเอง
Khan Ataur Rahman

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