IDENTITY
삽입 된 행 을 얻는 가장 좋은 방법은 무엇입니까 ?
내가 알고 @@IDENTITY
하고 IDENT_CURRENT
하고 SCOPE_IDENTITY
있지만 각에 부착 된 장점과 단점을 이해하지 않습니다.
누군가 차이점과 언제 사용해야하는지 설명해 주시겠습니까?
OUTPUT
SQL Server 의 절 보다 우선합니다 .
IDENTITY
삽입 된 행 을 얻는 가장 좋은 방법은 무엇입니까 ?
내가 알고 @@IDENTITY
하고 IDENT_CURRENT
하고 SCOPE_IDENTITY
있지만 각에 부착 된 장점과 단점을 이해하지 않습니다.
누군가 차이점과 언제 사용해야하는지 설명해 주시겠습니까?
OUTPUT
SQL Server 의 절 보다 우선합니다 .
답변:
@@IDENTITY
모든 범위에서 현재 세션의 테이블에 대해 생성 된 마지막 ID 값을 반환합니다. 범위가 다르므로 여기서주의해야합니다 . 현재 명령문 대신 트리거에서 값을 얻을 수 있습니다.
SCOPE_IDENTITY()
현재 세션 및 현재 범위의 테이블에 대해 생성 된 마지막 ID 값을 반환합니다. 일반적으로 사용하고 싶은 것 .
IDENT_CURRENT('tableName')
모든 세션 및 범위에서 특정 테이블에 대해 생성 된 마지막 ID 값을 반환합니다. 이것은 위의 두 가지가 당신이 필요로하지 않는 경우 ( 매우 드문 경우 ) 값을 원하는 테이블을 지정할 수있게합니다 . 또한 @ Guy Starbuck이 언급했듯이 "레코드를 삽입하지 않은 테이블의 현재 IDENTITY 값을 얻으려는 경우이를 사용할 수 있습니다."
명령문 의 OUTPUT
절 을 INSERT
통해 해당 명령문을 통해 삽입 된 모든 행에 액세스 할 수 있습니다. 특정 문장에 적용되므로 위의 다른 기능보다 더 간단 합니다. 그러나 조금 더 장황하고 (테이블 변수 / 임시 테이블에 삽입 한 다음 쿼리해야 함), 명령문이 롤백되는 오류 시나리오에서도 결과를 제공합니다. 즉, 쿼리에서 병렬 실행 계획을 사용하는 경우 이것이 병렬 처리를 해제하지 않는 ID를 얻는 유일한 방법 입니다. 그러나 트리거 전에 실행되며 트리거 생성 값을 반환하는 데 사용할 수 없습니다.
output
당신은 결과를 저장하기 위해 임시 테이블을 생성하고 쿼리 할 필요가 없습니다. 그냥 생략 할 into
출력 조항의 일부를 그리고 그것은 결과 집합을 출력 할 것이다.
OUTPUT
트리거를 사용하지 않고 에러를 처리하는 한 "최고"이지만 SCOPE_IDENTITY
가장 간단하고 거의 문제가 없다
삽입 된 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
OUTPUT
SQL 서버 2005 좋아 보이는 이전에 2000 만 SQL 서버이고, 그래서 그것을하지 않고있다가,
나는 다른 사람들과 같은 말을하고 있기 때문에 모든 사람들이 맞습니다. 나는 그것을 더 명확하게하려고합니다.
@@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)
scope_identity()
)이 병렬 계획을 얻는 것은 매우 드문 일 입니다. 그리고이 버그는이 답변보다 1 년 이상 전에 수정되었습니다.
output
대신 사용할 모든 SQL을 다시 작성하는 것이 유일한 해결책이었습니다 scope_identity()
. 답변에서 클러스터링에 대한 FUD를 제거했습니다.
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이 잘못되기 때문입니다.
테이블에 트리거가 있으면 반환 된 타임 스탬프가 정확 하지 않습니다 . 따라서 별도 의을 사용해야합니다 SELECT
.
그리고 잘못된 행 버전을 기꺼이 겪을지라도, 분리를 수행하는 다른 이유 는 테이블 변수에 SELECT
a 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
TurboEncabulators
:)
@@ IDENTITY, SCOPE_IDENTITY 및 IDENT_CURRENT는 테이블의 IDENTITY 열에 삽입 된 마지막 값을 반환한다는 점에서 비슷한 함수입니다.
@@ IDENTITY 및 SCOPE_IDENTITY는 현재 세션의 모든 테이블에서 생성 된 마지막 ID 값을 반환합니다. 그러나 SCOPE_IDENTITY는 현재 범위 내에서만 값을 반환합니다. @@ IDENTITY는 특정 범위로 제한되지 않습니다.
IDENT_CURRENT는 범위와 세션에 의해 제한되지 않습니다. 지정된 테이블로 제한됩니다. IDENT_CURRENT는 모든 세션 및 범위의 특정 테이블에 대해 생성 된 ID 값을 반환합니다. 자세한 내용은 IDENT_CURRENT를 참조하십시오.
@@ IDENTITY 는 현재 SQL 연결을 사용하여 삽입 된 마지막 ID입니다. 이것은 삽입 저장 프로 시저에서 반환하기에 좋은 값입니다. 여기서 새 레코드에 삽입 된 ID 만 있으면되고 이후에 더 많은 행이 추가되었는지는 신경 쓰지 않습니다.
SCOPE_IDENTITY 는 현재 SQL 연결을 사용하여 삽입 된 마지막 ID이며 현재 범위에서, 즉 삽입 후 트리거를 기반으로 두 번째 IDENTITY가 삽입 된 경우 SCOPE_IDENTITY에 반영되지 않으며 수행 한 삽입 만 반영됩니다 . 솔직히, 나는 이것을 사용할 이유가 없었습니다.
IDENT_CURRENT (tablename) 은 연결 또는 범위에 관계없이 삽입 된 마지막 ID입니다. 레코드를 삽입하지 않은 테이블의 현재 IDENTITY 값을 가져 오려는 경우이를 사용할 수 있습니다.
다른 버전의 SQL Server와 대화 할 수는 없지만 2012 년에는 직접 출력하는 것이 좋습니다. 임시 테이블을 신경 쓸 필요가 없습니다.
INSERT INTO MyTable
OUTPUT INSERTED.ID
VALUES (...)
그런데이 기술은 여러 행을 삽입 할 때도 작동합니다.
INSERT INTO MyTable
OUTPUT INSERTED.ID
VALUES
(...),
(...),
(...)
산출
ID
2
3
4
OUTPUT
. 임시 테이블이 필요하지 않으면 쿼리가 훨씬 간단 해집니다.
항상 scope_identity ()를 사용하면 다른 어떤 것도 필요하지 않습니다.
를 uuid
만들고 열에 삽입하십시오. 그러면 UUID로 행을 쉽게 식별 할 수 있습니다. 이것이 100 % 작동하는 유일한 솔루션입니다. 다른 모든 솔루션이 너무 복잡하거나 동일한 경우에 작동하지 않습니다. 예 :
1) 행 만들기
INSERT INTO table (uuid, name, street, zip)
VALUES ('2f802845-447b-4caa-8783-2086a0a8d437', 'Peter', 'Mainstreet 7', '88888');
2) 행 생성
SELECT * FROM table WHERE uuid='2f802845-447b-4caa-8783-2086a0a8d437';
uuid
데이터베이스에서에 대한 색인을 작성하는 것을 잊지 마십시오 . 따라서 행이 더 빨리 발견됩니다.
https://www.npmjs.com/package/uuid
. const uuidv4 = require('uuid/v4'); const uuid = uuidv4()
행의 신원을 보장하는 또 다른 방법은 삽입 신원 값을 지정하고를 사용하는 SET IDENTITY_INSERT ON
다음과 OFF
. 이를 통해 ID 값이 무엇인지 정확하게 알 수 있습니다! 값을 사용하지 않는 한이 값을 ID 열에 삽입 할 수 있습니다.
CREATE TABLE #foo
(
fooid INT IDENTITY NOT NULL,
fooname VARCHAR(20)
)
SELECT @@Identity AS [@@Identity],
Scope_identity() AS [SCOPE_IDENTITY()],
Ident_current('#Foo') AS [IDENT_CURRENT]
SET IDENTITY_INSERT #foo ON
INSERT INTO #foo
(fooid,
fooname)
VALUES (1,
'one'),
(2,
'Two')
SET IDENTITY_INSERT #foo OFF
SELECT @@Identity AS [@@Identity],
Scope_identity() AS [SCOPE_IDENTITY()],
Ident_current('#Foo') AS [IDENT_CURRENT]
INSERT INTO #foo
(fooname)
VALUES ('Three')
SELECT @@Identity AS [@@Identity],
Scope_identity() AS [SCOPE_IDENTITY()],
Ident_current('#Foo') AS [IDENT_CURRENT]
-- YOU CAN INSERT
SET IDENTITY_INSERT #foo ON
INSERT INTO #foo
(fooid,
fooname)
VALUES (10,
'Ten'),
(11,
'Eleven')
SET IDENTITY_INSERT #foo OFF
SELECT @@Identity AS [@@Identity],
Scope_identity() AS [SCOPE_IDENTITY()],
Ident_current('#Foo') AS [IDENT_CURRENT]
SELECT *
FROM #foo
이것은 다른 소스에서 데이터를로드하거나 두 데이터베이스의 데이터를 병합하는 경우 매우 유용한 기술입니다.
이것이 이전 스레드이지만 서버를 재부팅 한 후 ID 값의 간격과 같이 이전 버전의 SQL Server에서 IDENTITY 열의 함정을 피하는 새로운 방법 이 있습니다. SQL Server 2016부터 시퀀스를 사용할 수 있으며 TSQL을 사용하여 SEQUENCE 개체를 만드는 가장 새로운 방법입니다. 이를 통해 SQL Server에서 고유 한 숫자 시퀀스 개체를 만들고 증가 방법을 제어 할 수 있습니다.
예를 들면 다음과 같습니다.
CREATE SEQUENCE CountBy1
START WITH 1
INCREMENT BY 1 ;
GO
그런 다음 TSQL에서 다음 순서 ID를 얻기 위해 다음을 수행합니다.
SELECT NEXT VALUE FOR CountBy1 AS SequenceID
GO
CREATE SEQUENCE 및 NEXT VALUE FOR 링크는 다음과 같습니다.
Insert Statement 다음에 이것을 추가해야합니다. 그리고 데이터가 삽입되는 테이블 이름을 확인하십시오. 지금 삽입 행의 영향을받는 행이 현재 행에 표시되지 않습니다.
IDENT_CURRENT('tableName')
INSERT INTO Table1(fields...) OUTPUT INSERTED.id VALUES (...)
또는 이전 방법 :INSERT INTO Table1(fields...) VALUES (...); SELECT SCOPE_IDENTITY();
ExecuteScalar ()를 사용하여 c #으로 가져올 수 있습니다.