[sql] 삽입 된 행의 정체성을 얻는 가장 좋은 방법은 무엇입니까?

IDENTITY삽입 된 행 을 얻는 가장 좋은 방법은 무엇입니까 ?

내가 알고 @@IDENTITY하고 IDENT_CURRENT하고 SCOPE_IDENTITY있지만 각에 부착 된 장점과 단점을 이해하지 않습니다.

누군가 차이점과 언제 사용해야하는지 설명해 주시겠습니까?



답변

  • @@IDENTITY모든 범위에서 현재 세션의 테이블에 대해 생성 된 마지막 ID 값을 반환합니다. 범위가 다르므로 여기서주의해야합니다 . 현재 명령문 대신 트리거에서 값을 얻을 수 있습니다.

  • SCOPE_IDENTITY()현재 세션 및 현재 범위의 테이블에 대해 생성 된 마지막 ID 값을 반환합니다. 일반적으로 사용하고 싶은 것 .

  • IDENT_CURRENT('tableName')모든 세션 및 범위에서 특정 테이블에 대해 생성 된 마지막 ID 값을 반환합니다. 이것은 위의 두 가지가 당신이 필요로하지 않는 경우 ( 매우 드문 경우 ) 값을 원하는 테이블을 지정할 수있게합니다 . 또한 @ Guy Starbuck이 언급했듯이 “레코드를 삽입하지 않은 테이블의 현재 IDENTITY 값을 얻으려는 경우이를 사용할 수 있습니다.”

  • 명령문 의 OUTPUTINSERT통해 해당 명령문을 통해 삽입 된 모든 행에 액세스 할 수 있습니다. 특정 문장에 적용되므로 위의 다른 기능보다 더 간단 합니다. 그러나 조금 더 장황하고 (테이블 변수 / 임시 테이블에 삽입 한 다음 쿼리해야 함), 명령문이 롤백되는 오류 시나리오에서도 결과를 제공합니다. 즉, 쿼리에서 병렬 실행 계획을 사용하는 경우 이것이 병렬 처리를 해제하지 않는 ID를 얻는 유일한 방법 입니다. 그러나 트리거 전에 실행되며 트리거 생성 값을 반환하는 데 사용할 수 없습니다.


답변

삽입 된 ID를 검색하는 가장 안전하고 정확한 방법은 출력 절을 사용하는 것입니다.

예를 들어 (다음 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


답변

나는 다른 사람들과 같은 말을하고 있기 때문에 모든 사람들이 맞습니다. 나는 그것을 더 명확하게하려고합니다.

@@IDENTITY클라이언트의 데이터베이스 연결에 의해 마지막으로 삽입 된 ID를 반환합니다.
대부분의 경우 정상적으로 작동하지만 때로는 트리거가 발생하여 모르는 새 행을 삽입하고 원하는 새 행 대신이 새 행에서 ID를 얻습니다.

SCOPE_IDENTITY()이 문제를 해결합니다. 데이터베이스에 보낸 SQL 코드에 마지막으로 삽입 한 ID를 반환 합니다. 트리거가 이동하여 추가 행을 작성하면 잘못된 값이 리턴되지 않습니다. 후 레이

IDENT_CURRENT누구나 삽입 한 마지막 ID를 반환합니다. 다른 응용 프로그램이 예기치 않은 시간에 다른 행을 삽입하면 해당 행 대신 ID가 표시됩니다.

안전하게 플레이하려면 항상을 사용하십시오 SCOPE_IDENTITY(). 고수 @@IDENTITY하고 누군가가 나중에 트리거를 추가하기로 결정하면 모든 코드가 중단됩니다.


답변

새로 삽입 된 행의 ID를 얻는 가장 좋은 (읽기 : 가장 안전한) 방법은 다음 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)


답변

더하다

SELECT CAST(scope_identity() AS int);

insert sql 문의 끝까지

NewId = command.ExecuteScalar()

그것을 검색합니다.


답변

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있으면 OUTPUT이 잘못되기 때문입니다.

  • 초기 삽입. 타임 스탬프 : 1
  • OUTPUT 절 출력 타임 스탬프 : 1
  • 트리거는 행을 수정합니다. 타임 스탬프 : 2

테이블에 트리거가 있으면 반환 된 타임 스탬프가 정확 하지 않습니다 . 따라서 별도 의을 사용해야합니다 SELECT.

그리고 잘못된 행 버전을 기꺼이 겪을지라도, 분리를 수행하는 다른 이유 는 테이블 변수에 SELECTa 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하는 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


답변

MSDN

@@ IDENTITY, SCOPE_IDENTITY 및 IDENT_CURRENT는 테이블의 IDENTITY 열에 삽입 된 마지막 값을 반환한다는 점에서 비슷한 함수입니다.

@@ IDENTITY 및 SCOPE_IDENTITY는 현재 세션의 모든 테이블에서 생성 된 마지막 ID 값을 반환합니다. 그러나 SCOPE_IDENTITY는 현재 범위 내에서만 값을 반환합니다. @@ IDENTITY는 특정 범위로 제한되지 않습니다.

IDENT_CURRENT는 범위와 세션에 의해 제한되지 않습니다. 지정된 테이블로 제한됩니다. IDENT_CURRENT는 모든 세션 및 범위의 특정 테이블에 대해 생성 된 ID 값을 반환합니다. 자세한 내용은 IDENT_CURRENT를 참조하십시오.

  • IDENT_CURRENT 는 테이블을 인수로 취하는 함수입니다.
  • 테이블에 트리거가 있으면 @@ IDENTITY 가 혼란스러운 결과를 반환 할 수 있습니다.
  • SCOPE_IDENTITY 는 대부분의 영웅입니다.