INSERT deyiminin (SQL Server) OUTPUT INTO yan tümcesinde kaynak sütunları kullanma


16

Bir toplu işleme ekleme deyimi yazıyorum ve kendim öğeleri arasında döngü ve eklenen her satır için SCOPE_IDENTITY () çağırmak yerine eklenen kimlikleri izlemek için bir geçici tablo kullanmak istiyorum.

Eklenmesi gereken veri (geçici) kimliği de başka bir tabloya da eklenmesi gereken diğer verilere bağlayan vardır, bu yüzden gerçek kimliği ve geçici kimliği çapraz referans gerekir.

Bu şimdiye kadar ne var bir örnek:

-- 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

Sorun, kimliği kabul etmek için OUTPUT INTO yan tümcesini alamıyorum, denedim @MyInsertData.IDve tabloya kendisine katılan diğer hileler, ama hiçbir şey işe yaramaz gibi görünüyor.

Yanıtlar:


28

Aslında, aynı şeyi elde etmek INSERTiçin bir MERGE. MERGEİfade aslında SQL Server'da "upserts" yapmanın oldukça düzgün bir yolu olsa da, yalnızca ekleme amacıyla kullanmanıza engel olacak hiçbir şey yoktur:

-- 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

MERGEBununla ilgili güzel şeylerden biri , kaynak sütunlara , yan tümcedeki yerleşik insertedve deletedtablolara erişmenize izin vermesidir OUTPUT.

Aslında test etmediğim için kodum hatalar içerebilir. Birkaç yıl önceki blog yayınım, sorgu performansı da dahil olmak üzere biraz daha ayrıntıya giriyor.


Bu harika! Bu sefer SQL Server 2005 desteği gerektiğinden bir döngüye bağlı kalmam gerekecek. Ancak bunu gelecekteki projeler için aklımda tutacağım. Teşekkürler!
Louis Somers

3
Harika, bu kabul edilen cevap olmalı.
Chris Peacock

3
Bu dba stackexchange yerine stackoverflow içinde olsaydı. Görünürlüğü çok az. Şaşırtıcı cevap.
Lordbalmon

3
İlk denemeden bir cazibe gibi çalıştı ... harika cevap!
BeemerGuy

5

Çıkış yan tümcesi, yalnızca hedef satırlardaki ve sabitlerdeki / değişkenlerdeki verilere erişebilir SELECT, bir tetikleyicide çalışıyormuş gibi , kaynağın başka bir yerindeki verilere erişemez .

https://docs.microsoft.com/tr-tr/sql/t-sql/queries/output-clause-transact-sql durumları:

Değiştirilen tablodaki sütunlara yapılan herhangi bir başvuru INSERTED veya DELETED önekiyle nitelendirilmelidir.

Bu nedenle, orijinal kimliğini elde etmek için hedef cümle içine eklemeniz gerekir;

-- 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

hedef nesnenin şemasını değiştirmek sizin durumunuzda pratik olmayabilir, bu yüzden bu geçerli olmayabilir.


3
Bu oldukça hayal kırıklığı. Anahtar olarak kullanılabilecek bir 2. sütun olmadığı sürece, bu, çıktı koşulunu senaryom için işe yaramaz hale getirir: --( Oh, en azından, denemeyi bırakıp döngüye devam edebilirim. Teşekkürler
Louis Somers
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.