Використання вихідних стовпців у пункті OUTPUT INTO для оператора INSERT (SQL Server)


16

Я пишу оператор вставки пакетної обробки і хотів би використовувати таблицю темпів для відстеження вставлених ідентифікаторів замість того, щоб переглядати самі елементи і викликати SCOPE_IDENTITY () для кожного вставленого рядка.

Дані, які потрібно вставити, мають (тимчасовий) ідентифікатор, що пов'язує його з іншими даними, які також слід вставити в іншу таблицю, тому мені потрібна перехресна посилання на фактичний Id та тимчасовий 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

Проблема полягає в тому, що я не можу отримати пункт OUTPUT INTO прийняти ідентифікатор, я намагався @MyInsertData.IDта інші хитрощі приєднання таблиці до себе, але, здається, нічого не працює.

Відповіді:


28

Насправді ви можете домогтися того ж, змінивши свій INSERTа MERGE. Хоча MERGEвислів насправді є досить акуратним способом зробити "покращення" на 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. Однак я пам’ятаю це про майбутні проекти. Дякую!
Луї Сомерс

3
Блискуче, це повинна бути прийнята відповідь.
Кріс Павич

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.

Отже, щоб отримати оригінальний ідентифікатор, вам потрібно буде включити його до таблиці призначення, щоб вивідний пункт міг повторити його, як-от так:

-- 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-го стовпця, який можна використовувати як ключ :-( О, ну, принаймні, я можу перестати пробувати і продовжувати циклічно. Спасибі.
Луї Сомерс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.