SQL Server-INSERT 후 반환 값


318

INSERT 문 후에 키-값을 다시 얻으려고합니다. 예 : 속성 이름과 ID가있는 테이블이 있습니다. id는 생성 된 값입니다.

    INSERT INTO table (name) VALUES('bob');

이제 동일한 단계에서 ID를 다시 얻고 싶습니다. 이것은 어떻게 이루어 집니까?

우리는 Microsoft SQL Server 2008을 사용하고 있습니다.


나는 여기에 유용한 응답을 발견 : [PreparedStatement의-와 문 복귀 생성 - 키] [1] [1] : stackoverflow.com/questions/4224228/...
라스 Ladegaard

답변:


477

별도의 SELECT가 필요하지 않습니다 ...

INSERT INTO table (name)
OUTPUT Inserted.ID
VALUES('bob');

이것은 비 IDENTITY 열 (예 : GUID)에서도 작동합니다.


29
좀 더 자세히 설명해 주시겠습니까? 이 예제에서 출력은 어디로 갑니까? 설명서 에는 테이블에 대한 예제 만 표시됩니다 (출력 사용 ...). 이상적으로 변수에 변수를 전달하고 싶습니다
JonnyRaa

2
@JonnyLeeds : 변수를 만들 수 없습니다 (테이블 변수가 아닌 경우). OUTPUT은 고객이나 테이블로 간다
gbn

7
불행히도, 테이블에 트리거를 추가하면 명령문이 깨지기 때문에 이것에 의존 할 수 없습니다! re : blogs.msdn.com/b/sqlprogrammability/archive/2008/07/11/…
hajikelist 2016 년

1
@hajikelist : 이것은 매우 중요한 경우이며 일반적으로 트리거의 SET NCOOUNT ON이 도움이됩니다. stackoverflow.com/questions/1483732/set-nocount-on-usage
gbn

5
@@ IDENTITY를 사용하지 마십시오. SCOPE_IDENTITY, 예, 그러나 @@ IDENTITY는 아닙니다. 신뢰할 수 없음
gbn

188

SCOPE_IDENTITY()새로운 ID 값을 얻는 데 사용

INSERT INTO table (name) VALUES('bob');

SELECT SCOPE_IDENTITY()

http://msdn.microsoft.com/en-us/library/ms190315.aspx


7
가정 id의 정체성이다
일리아 G

12
@ liho1eye-OP에서 ID 열 이름을이라고했습니다 id. 그렇습니다.
Curt

3
더 큰 시스템에서 많은 SQL이 동시에 실행되면 어떻게됩니까? 모든 요청에 ​​마지막으로 삽입 된 ID를 반환합니까?
Shiv

2
@Shiv "SCOPE_IDENTITY 반환 값은 현재 범위 내에서 삽입"
goodies4uall

45
INSERT INTO files (title) VALUES ('whatever'); 
SELECT * FROM files WHERE id = SCOPE_IDENTITY();

트리거가있는 테이블에서 OUTPUT 절 충돌과 관련하여 알려진 문제가 있으므로 가장 안전한 방법입니다. 테이블에 현재 트리거가없는 경우에도이를 신뢰할 수 없게 만듭니다. 누군가 줄을 추가하면 애플리케이션이 중단됩니다. 시한 폭탄 종류의 행동.

자세한 설명은 msdn 기사를 참조하십시오.

http://blogs.msdn.com/b/sqlprogrammability/archive/2008/07/11/update-with-output-clause-triggers-and-sqlmoreresults.aspx


트리거에 SET NOCOUNT ON을 추가하지 않은 경우에만 해당됩니다. docs.microsoft.com/en-us/sql/database-engine/configure-windows/…
gbn

이 @gbn 우리의 레거시 환경을위한 옵션이 아닙니다
hajikelist

@hajikelist 우리 모두는 레거시를 가지고 있지만, 트리거가 OUTPUT을 망칠 위험은 적습니다. 누군가 트리거를 추가하는 경우 트리거 방법을 알아야합니다 (주로 제어권이 있음을 암시 함). 개발자를 훈련시켜야합니다. 어느 시점에서 해당 SQL 버전이 더 이상 없을 때 마이그레이션해야합니다. 지원 등으로 인해 트리거로 인해 결과 집합이 발생하지 않습니다. 어쨌든 INSTEAD OF 트리거가 있으면 SCOPE_IDENTITY가 작동하지 않을 수 있기 때문에 가장 좋은 대답은 아닙니다 ( stackoverflow.com/questions/908257/… )
gbn

@gbn-나는 이런 바보 같은 것을 피하고 싶습니다. 모든 개발자에게 "모든 트리거에서 '앱 설명을 깨지 말 것'을 추가하는 것을 잊지 마십시오." - 그건 가지 셔도됩니다. "대신"시나리오는 가장 중요한 경우입니다.
hajikelist

더 안전한 대답은 응용 프로그램이이 쿼리에서 반환 된 다른 쿼리를 실행하도록하는 것입니다. 백엔드에서 수행되는 한 성능 저하는 사람들 그룹에서 개발을 관리하는 단순성에 가치가 있으며 가장자리가있는 미친 기능보다 표준에 더 가깝습니다. 차라리 엣지 케이스가 내 코드에 있고 플랫폼에서 피하고 싶습니다. 그냥 내 의견은 놀라지 않습니다 :)
Dan Chase

33

Entity Framework는 gbn의 답변과 비슷한 것을 수행합니다.

DECLARE @generated_keys table([Id] uniqueidentifier)

INSERT INTO Customers(FirstName)
OUTPUT inserted.CustomerID INTO @generated_keys
VALUES('bob');

SELECT t.[CustomerID]
FROM @generated_keys AS g 
   JOIN dbo.Customers AS t 
   ON g.Id = t.CustomerID
WHERE @@ROWCOUNT > 0

출력 결과는 임시 테이블 변수에 저장된 후 클라이언트로 다시 선택됩니다. 문제를 알고 있어야합니다.

삽입은 둘 이상의 행을 생성 할 수 있으므로 변수가 둘 이상의 행을 보유 할 수 있으므로 둘 이상을 리턴 할 수 있습니다 ID

EF가 임시 테이블을 내부 테이블과 다시 결합하는 이유를 알 수 없습니다 (어떤 상황에서 두 가지가 일치하지 않을까요).

그러나 이것이 EF가하는 일입니다.

SQL Server 2008 이상 만 2005 년이면 운이 나쁘다.


2
EF가 수행하는 이유는 Customer영향을받는 다른 DB 측 로직 (예 : DEFAULT일부 열, 테이블의 트리거 등) 이있을 수 있으므로 삽입 된 레코드의 다른 모든 변경 사항을 "볼"수 있도록하기 위함입니다 . 삽입에 사용 된 엔티티 (객체)이므로 클라이언트 측은 ID와 행의 현재 상태를 나타내는 다른 모든 것을 가진 고객 오브젝트를 가져옵니다.
힐라리 온

EF를 사용하지 않는 또 다른 이유.
cskwg

11

@@IDENTITY 마지막으로 삽입 된 ID 값을 반환하는 시스템 함수입니다.


4
@@ IDENTITY를 사용하지 말 것을 권장해야합니다. 스레드 안전이 훨씬 정확하지는 않습니다 (SCOPE_IDENTITY ()에 대한 @Curt의 답변 참조).
zanlok

10

삽입 후 종료하는 방법에는 여러 가지가 있습니다

테이블에 데이터를 삽입 할 때 OUTPUT 절을 사용하여 테이블에 삽입 된 데이터의 복사본을 반환 할 수 있습니다. OUTPUT 절은 두 가지 기본 형식 인 OUTPUT 및 OUTPUT INTO를 사용합니다. 데이터를 호출 응용 프로그램으로 리턴하려면 OUTPUT 양식을 사용하십시오. 데이터를 테이블 또는 테이블 변수로 리턴하려면 OUTPUT INTO 양식을 사용하십시오.

DECLARE @MyTableVar TABLE (id INT,NAME NVARCHAR(50));

INSERT INTO tableName
(
  NAME,....
)OUTPUT INSERTED.id,INSERTED.Name INTO @MyTableVar
VALUES
(
   'test',...
)

IDENT_CURRENT : 세션에서 특정 테이블 또는 뷰에 대해 생성 된 마지막 ID를 반환합니다.

SELECT IDENT_CURRENT('tableName') AS [IDENT_CURRENT]

SCOPE_IDENTITY : 같은 세션과 같은 범위에서 마지막 아이디를 반환합니다. 범위는 저장 프로 시저 / 트리거 등입니다.

SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY];  

@@ IDENTITY : 동일한 세션에서 마지막 ID를 반환합니다.

SELECT @@IDENTITY AS [@@IDENTITY];

1
@RezaJenabi 6 월, 풋가 밖으로 아주 좋은 일을하고, 테이블에 여러 ID를 찾을 것보다 낫다. 내가 사용 out put에 대한 bulk insert및에 의해 삽입합니다 select statement. 귀하의 제안에 감사드립니다
Amirhossein

5

가장 확실한 솔루션은 SCOPE_IDENTITY() 입니다.

동일한 범위에서 두 개의 삽입을 호출 할 수 있으므로 모든 삽입 후 범위 ID를 가져와 변수에 저장해야합니다.

ident_current그리고 @@identity그들이 일을하지만 그들이 안전 범위 아니다. 큰 응용 프로그램에서 문제가 발생할 수 있습니다

  declare @duplicataId int
  select @duplicataId =   (SELECT SCOPE_IDENTITY())

자세한 내용은 여기에 Microsoft 문서


1
이것을 간단하게 할 수 있습니다select @duplicataId = SCOPE_IDENTITY()
pcnate

1
OUTPUT조항이 더 좋고 더 순수한 해결책입니다 :)
Dale K

OUTPUT INTO는 매우 느립니다.
cskwg


1

insert 명령 후에 마지막으로 삽입 된 ID를 얻는 방법에는 여러 가지가 있습니다.

  1. @@IDENTITY : Table 및 값을 생성 한 명령문 범위에 관계없이 현재 세션에서 Connection에 생성 된 마지막 Identity 값을 반환합니다.
  2. SCOPE_IDENTITY(): 테이블에 관계없이 현재 연결의 현재 범위에서 insert 문으로 생성 된 마지막 ID 값을 리턴합니다.
  3. IDENT_CURRENT(‘TABLENAME’): 모든 연결, 세션 또는 범위에 관계없이 지정된 테이블에서 생성 된 마지막 ID 값을 반환합니다. IDENT_CURRENT는 범위와 세션에 의해 제한되지 않습니다. 지정된 테이블로 제한됩니다.

이제 어느 것이 내 요구 사항과 정확히 일치하는지 결정하기가 더 어려워 보입니다.

나는 주로 SCOPE_IDENTITY ()를 선호합니다.

insert 문에서 TableName과 함께 select SCOPE_IDENTITY ()를 사용하면 예상대로 정확한 결과를 얻을 수 있습니다.

출처 : CodoBee


0

이것은 SQL Server에서 ID를 ID 열로 사용하는 테이블에 삽입 할 때 OUTPUT INSERTED를 사용하는 방법입니다.

'myConn is the ADO connection, RS a recordset and ID an integer
Set RS=myConn.Execute("INSERT INTO M2_VOTELIST(PRODUCER_ID,TITLE,TIMEU) OUTPUT INSERTED.ID VALUES ('Gator','Test',GETDATE())")
ID=RS(0)

0

삽입 문에 select 문을 추가 할 수 있습니다. 정수 myInt = table1 (FName) 값에 삽입 ( 'Fred'); Scope_Identity ()를 선택하십시오. 스케일러를 실행할 때 ID 값을 반환합니다.



-4

* 연결 문자열에서 매개 변수 순서가 중요한 경우가 있습니다. * 공급자 매개 변수의 위치는 행을 추가 한 후 레코드 세트 커서를 끊을 수 있습니다. 우리는이 동작을 SQLOLEDB 공급자와 함께 보았습니다.

행이 추가 된 후 제공자가 연결 문자열 의 첫 번째 매개 변수 로 지정되지 않으면 행 필드를 사용할 수 없습니다 . 첫 번째 매개 변수를 제외하고 공급자가 연결 문자열의 아무 곳에 나 있으면 새로 삽입 된 행 필드를 사용할 수 없습니다. Provider를 첫 번째 매개 변수로 옮길 때 행 필드가 마술처럼 나타납니다.


1
이 의견에 대한 답변 / 질문과 관련된 내용을 알려주시겠습니까? 나는 그것이 모자 / 대담 할 가치가 있다고 생각하지 않습니다. 답변이 도움이된다고 생각되면 사용자가 투표를합니다.
n__o

방금 추가 한 행을 식별하는 유효한 필드가 없기 때문에 많은 사용자가이 페이지를 방문했을 것입니다. 우리가 발견 한이 동작 (연결 문자열에서 매개 변수의 순서를 변경하면 새로 추가 된 행에 즉시 액세스 할 수 있음)이 너무 기괴하여 대문자로 언급 할 가치가 있다고 생각했습니다. 특히 사람들이 새로운 것을 원하는 이유를 해결할 가능성이 높기 때문에 행 ID 및 해당 행의 다른 필드 단순히 공급자를 첫 번째 매개 변수로두면 문제가 사라집니다.
David Guidos

답을 편집하고 개선해야합니다. 그것은 현재 시끄럽고 괜찮은 답변이나 시도로 나오지 않습니다
James

"잡음"이란 정확히 무엇을 의미합니까? 불만을 설명해야합니다. 가능한 한 간단합니다. 연결 문자열에서 매개 변수의 순서를 변경하면 삽입 후 행 데이터를 사용할 수 있는지 여부에 영향을 줄 수 있습니다.
David Guidos
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.