การใช้คอลัมน์แหล่งที่มาในส่วนคำสั่ง OUTPUT INTO ของคำสั่ง INSERT (SQL Server)


16

ฉันกำลังเขียนคำสั่งแทรกการประมวลผลแบบแบทช์และต้องการใช้ตาราง temp เพื่อติดตาม ID ที่ถูกแทรกแทนการวนลูปผ่านไอเท็มด้วยตัวเองและเรียก SCOPE_IDENTITY () สำหรับแต่ละแถวที่แทรก

ข้อมูลที่ต้องถูกแทรกมี (ชั่วคราว) ของ ID ที่เชื่อมโยงไปยังข้อมูลอื่นที่ควรถูกแทรกลงในตารางอื่นดังนั้นฉันต้องการอ้างอิงไขว้ของรหัสจริงและรหัสชั่วคราว

นี่คือตัวอย่างของสิ่งที่ฉันมี:

-- The existing table 
DECLARE @MyTable TABLE (ID INT IDENTITY(1,1), [Name] NVARCHAR(MAX));

-- My data I want to insert
DECLARE @MyInsertData TABLE (ID INT, [Name] NVARCHAR(MAX));
INSERT INTO @MyInsertData ( ID,Name)
VALUES ( -1 , 'bla'),(-2,'test'),(-3,'last');

DECLARE @MyCrossRef TABLE ([NewId] INT, OldId INT);

INSERT INTO @MyTable ( [Name] )
   OUTPUT Inserted.ID, INS.ID INTO @MyCrossRef
   SELECT [NAME] FROM @MyInsertData INS

-- Check the result
SELECT * FROM @MyCrossRef

ปัญหาคือว่าฉันไม่สามารถรับเอาท์พุทเป็นคำสั่งที่จะยอมรับ ID ฉันได้ลอง@MyInsertData.IDและเทคนิคอื่น ๆ เข้าร่วมตารางเพื่อตัวเอง แต่ดูเหมือนว่าไม่มีอะไรทำงาน

คำตอบ:


28

ที่จริงแล้วคุณจะประสบความสำเร็จในสิ่งเดียวกันโดยการเปลี่ยนไปINSERT MERGEในขณะที่MERGEคำสั่งนั้นเป็นวิธีที่ค่อนข้างเรียบร้อยในการทำ "upserts" ใน SQL Server แต่ก็ไม่มีอะไรที่จะห้ามไม่ให้คุณใช้มันเพื่อจุดประสงค์ในการแทรกเท่านั้น:

-- The existing table 
DECLARE @MyTable TABLE (ID INT IDENTITY(1,1), [Name] NVARCHAR(MAX));

-- My data I want to insert
DECLARE @MyInsertData TABLE (ID INT, [Name] NVARCHAR(MAX));
INSERT INTO @MyInsertData ( ID,Name)
VALUES ( -1 , 'bla'),(-2,'test'),(-3,'last');

DECLARE @MyCrossRef TABLE ([NewId] INT, OldId INT);

MERGE INTO @MyTable AS dest
USING @MyInsertData AS ins ON 1=0   -- always false

WHEN NOT MATCHED BY TARGET          -- happens for every row, because 1 is never 0
    THEN INSERT ([Name])
         VALUES (ins.[NAME])

OUTPUT inserted.ID, ins.ID
INTO @MyCrossRef (NewId, OldId);

-- Check the result
SELECT * FROM @MyCrossRef

หนึ่งในสิ่งที่ดีเกี่ยวกับMERGEคือมันช่วยให้คุณสามารถเข้าถึงคอลัมน์ต้นฉบับเช่นเดียวกับในตัวinsertedและdeletedตารางในOUTPUTอนุประโยค

รหัสของฉันอาจมีข้อผิดพลาดเนื่องจากฉันไม่ได้ทดสอบจริง โพสต์บล็อกของฉันเมื่อไม่กี่ปีที่ผ่านมามีรายละเอียดเพิ่มเติมเล็กน้อยรวมถึงประสิทธิภาพของการสืบค้น


เยี่ยมมาก! รอบนี้ฉันจะต้องติดกับลูปเพราะต้องการการสนับสนุน SQL Server 2005 อย่างไรก็ตามฉันจะจำเรื่องนี้ไว้สำหรับโครงการในอนาคต ขอบคุณ!
Louis

3
ยอดเยี่ยมนี่ควรเป็นคำตอบที่ยอมรับได้
Chris Peacock

3
ต้องการสิ่งนี้อยู่ใน stackoverflow แทน dba stackexchange มันมีทัศนวิสัยน้อยเกินไป คำตอบที่น่าอัศจรรย์
Lordbalmon

3
ทำงานเหมือนจับใจตั้งแต่ครั้งแรกลอง ... คำตอบที่ยอดเยี่ยม!
BeemerGuy

5

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

https://docs.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sqlสถานะ:

การอ้างอิงถึงคอลัมน์ในตารางที่ถูกแก้ไขใด ๆ จะต้องผ่านการรับรองด้วยคำนำหน้า INSERTED หรือ DELETED

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

-- The existing table 
DECLARE @MyTable TABLE (ID INT IDENTITY(1,1), [Name] NVARCHAR(MAX), SourceID INT);

-- My data I want to insert
DECLARE @MyInsertData TABLE (ID INT, [Name] NVARCHAR(MAX));
INSERT INTO @MyInsertData ( ID,Name)
VALUES ( -1 , 'bla'),(-2,'test'),(-3,'last');

DECLARE @MyCrossRef TABLE ([NewId] INT, OldId INT);

INSERT INTO @MyTable ( [Name], SourceID )
   OUTPUT Inserted.ID, Inserted.SourceID INTO @MyCrossRef
   SELECT [NAME], ID FROM @MyInsertData INS

-- Check the result
SELECT * FROM @MyCrossRef

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


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