INSERT 문의 OUTPUT INTO 절에서 소스 열 사용 (SQL Server)


16

배치 처리 삽입 문을 작성 중이며 임시 테이블을 사용하여 항목을 직접 루핑하고 삽입 된 각 행에 대해 SCOPE_IDENTITY ()를 호출하는 대신 삽입 된 ID를 추적하려고합니다.

삽입 해야하는 데이터에는 (임시) ID가 다른 테이블에 삽입 해야하는 다른 데이터와 연결되어 있으므로 실제 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

문제는 ID를 수락하기 위해 OUTPUT INTO 절을 얻을 수 없다는 @MyInsertData.ID것과 테이블을 결합하는 다른 트릭을 시도 했지만 아무것도 작동하지 않는 것입니다.

답변:


28

사실, 당신은 당신을 변경하여 같은 일을 달성 할 수 INSERTA를 MERGE. 그동안 MERGE문은 SQL Server의 "upserts"을 할 수있는 꽤 깔끔한 방법은 사실, 그냥 삽입하는 용도로 사용에서 당신을 중지 아무것도 없다 :

-- 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당신이 액세스 할 수 있다는 것입니다 소스 열을 내장뿐만 아니라 inserteddeleted의 테이블 OUTPUT절.

실제로 테스트하지 않은 코드에 오류가있을 수 있습니다. 몇 년 전의 내 블로그 게시물 은 쿼리 성능을 포함하여 조금 더 자세히 설명합니다.


대단해! 이번에는 SQL Server 2005 지원이 필요하기 때문에 루프를 고수해야합니다. 그러나 나는 미래의 프로젝트를 위해 이것을 명심할 것이다. 감사!
루이스 소 머스

3
훌륭합니다. 이것은 정답입니다.
Chris Peacock

3
이것이 dba stackexchange 대신 stackoverflow에 있었기를 바랍니다. 시인성이 너무 적습니다. 놀라운 답변입니다.
Lordbalmon

3
첫 번째 시도에서 매력처럼 작동했습니다 ... 멋진 답변!
BeemerGuy

5

output 절은 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 열이 없다면 그건 내 시나리오에 쓸모 출력 절을 렌더링
루이 써머
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.