728x90
반응형
테이블을 생성할 때, 일련번호를 할당하기 위하여 IDENTITY를 사용하게 됩니다. IDENTITY를 사용하할 때, 삽입한 행의 일련번호를 얻기 위하여 흔히 @@IDENTITY 함수를 자주 이용하게 되는데, @@IDENTITY 함수를 사용할 때 주의할 점이 있습니다.
@@IDENTITY 함수는 현재 세션에서 삽입된 마지막 IDENTITY 값을 반환합니다. 따라서 트리거에서 다른 테이블의 IDENTITY가 새로 추가되거나 하게 되면 원치 않는 결과를 가져오게 됩니다.(@@IDENTITY 함수가 트리거에서 삽입된 IDENTITY 값을 반환함)
그래서 현재 범위(하나의 저장프로시저 내, 하나의 쿼리문 내 ...)내에서 마지막으로 추가된 IDENTITY 다음 값을 얻을 때는 SCOPE_IDENTITY() 함수를 사용해야 합니다.
IDENT_CURRENT() 함수는 해당 테이블의 호출 시점의 마지막 IDENTITY 값을 반환합니다. 따라서 그 값이 다음에도 마지막 값이라고 보장할 수 없습니다. 왜냐하면 다른 세션에서 새로운 행을 추가한 경우에는 그 값이 달라지기 때문입니다.
예제를 보면서 @@IDENTITY와 SCOPE_IDENTITY() 함수의 차이를 알아 보겠습니다.
먼저 다음과 같이 테이블 2개와 트리거를 생성합니다. 트리거는 TRI_TEST 테이블에 데이터를 입력하면 TRI_TEST_LOG 테이블로 로그가 기록되도록 만들었습니다.
그리고 TRI_TEST 테이블에 데이터를 입력하고 그 결과를 확인하여 봅니다.
그리고 다음과 같이 기존에 입력한 데이터를 갱신합니다.
위 실행결과를 보시면 데이터는 갱신이 되었고, @@IDENTITY, SCOPE_IDENTITY(), IDENT_CURRENT() 함수간 반환값이 차이도 없습니다.
마지막으로 다시 1개의 데이터와 2개의 행을 갱신하여 봅니다.
데이터를 입력하고 각 IDENTITY 값을 얻는 함수들을 보면, @@IDENTTIY 값이 5가 아니라 7이 나오는 것을 확인하실 수 있습니다. 이것은 현재 세션 즉 TRI_TEST 테이블에 데이터를 갱신하면 트리거가 실행되면서 TRI_TEST_LOG 테이블에 로그가 기록되며 TRI_TEST_LOG 테이블의 IDENTITY가 새로 추가됩니다. @@IDENTITY 함수는 현재 세션에서 마지막으로 삽입된 IDENTITY 값으로 반환하기 때문에 TRI_TEST_LOG 테이블에 삽입된 마지막 IDENTITY 값인 7이 반환됩니다.
그리고, 앞의 데이터 삽입 결과에서도 @@IDENTITY 함수의 결과는 TRI_TEST의 마지막 삽입된 IDENTITY 값이 아니라, 트리거에 의하여 삽입된 TRI_TEST_LOG 테이블의 마지막 IDENTTIY 값이 반환된 것입니다.
@@IDENTITY 함수는 현재 세션에서 삽입된 마지막 IDENTITY 값을 반환합니다. 따라서 트리거에서 다른 테이블의 IDENTITY가 새로 추가되거나 하게 되면 원치 않는 결과를 가져오게 됩니다.(@@IDENTITY 함수가 트리거에서 삽입된 IDENTITY 값을 반환함)
그래서 현재 범위(하나의 저장프로시저 내, 하나의 쿼리문 내 ...)내에서 마지막으로 추가된 IDENTITY 다음 값을 얻을 때는 SCOPE_IDENTITY() 함수를 사용해야 합니다.
IDENT_CURRENT() 함수는 해당 테이블의 호출 시점의 마지막 IDENTITY 값을 반환합니다. 따라서 그 값이 다음에도 마지막 값이라고 보장할 수 없습니다. 왜냐하면 다른 세션에서 새로운 행을 추가한 경우에는 그 값이 달라지기 때문입니다.
예제를 보면서 @@IDENTITY와 SCOPE_IDENTITY() 함수의 차이를 알아 보겠습니다.
먼저 다음과 같이 테이블 2개와 트리거를 생성합니다. 트리거는 TRI_TEST 테이블에 데이터를 입력하면 TRI_TEST_LOG 테이블로 로그가 기록되도록 만들었습니다.
CREATE TABLE TRI_TEST ( tri_no INT IDENTITY(1, 1) NOT NULL , data VARCHAR(10) NULL , tno INT NULL ); CREATE TABLE TRI_TEST_LOG ( log_no INT IDENTITY(1, 1) NOT NULL , tri_no INT NOT NULL , mode CHAR(1) NOT NULL , log_date DATETIME NOT NULL ); CREATE TRIGGER tr_TRI_TEST ON TRI_TEST AFTER INSERT, UPDATE, DELETE AS BEGIN IF EXISTS(SELECT * FROM deleted) BEGIN IF EXISTS(SELECT * FROM inserted) INSERT INTO TRI_TEST_LOG SELECT tri_no, 'U', GETDATE() FROM deleted WHERE 1 = 1 AND tno IS NOT NULL ELSE INSERT INTO TRI_TEST_LOG SELECT tri_no, 'D', GETDATE() FROM deleted END ELSE BEGIN INSERT INTO TRI_TEST_LOG SELECT tri_no, 'I', GETDATE() FROM INSERTED END END; GO
그리고 TRI_TEST 테이블에 데이터를 입력하고 그 결과를 확인하여 봅니다.
INSERT INTO TRI_TEST VALUES ('AA', NULL); INSERT INTO TRI_TEST VALUES ('AA', NULL); INSERT INTO TRI_TEST VALUES ('AA', NULL); INSERT INTO TRI_TEST VALUES ('AA', NULL); SELECT * FROM TRI_TEST GO SELECT * FROM TRI_TEST_LOG GO SELECT @@IDENTITY, SCOPE_IDENTITY(), IDENT_CURRENT('TRI_TEST'); GO
그리고 다음과 같이 기존에 입력한 데이터를 갱신합니다.
UPDATE TRI_TEST SET DATA = 'UU', tno = 1 WHERE tri_no = 3; UPDATE TRI_TEST SET DATA = 'TT', tno = 2 WHERE tri_no = 4; GO SELECT * FROM TRI_TEST GO SELECT * FROM TRI_TEST_LOG GO SELECT @@IDENTITY, SCOPE_IDENTITY(), IDENT_CURRENT('TRI_TEST'); GO
위 실행결과를 보시면 데이터는 갱신이 되었고, @@IDENTITY, SCOPE_IDENTITY(), IDENT_CURRENT() 함수간 반환값이 차이도 없습니다.
마지막으로 다시 1개의 데이터와 2개의 행을 갱신하여 봅니다.
INSERT INTO TRI_TEST VALUES ('AB', NULL); GO UPDATE TRI_TEST SET DATA = 'UU', tno = 1 WHERE tri_no = 3; UPDATE TRI_TEST SET DATA = 'TT', tno = 2 WHERE tri_no = 4; GO SELECT * FROM TRI_TEST GO SELECT * FROM TRI_TEST_LOG GO SELECT @@IDENTITY, SCOPE_IDENTITY(), IDENT_CURRENT('TRI_TEST'); GO
데이터를 입력하고 각 IDENTITY 값을 얻는 함수들을 보면, @@IDENTTIY 값이 5가 아니라 7이 나오는 것을 확인하실 수 있습니다. 이것은 현재 세션 즉 TRI_TEST 테이블에 데이터를 갱신하면 트리거가 실행되면서 TRI_TEST_LOG 테이블에 로그가 기록되며 TRI_TEST_LOG 테이블의 IDENTITY가 새로 추가됩니다. @@IDENTITY 함수는 현재 세션에서 마지막으로 삽입된 IDENTITY 값으로 반환하기 때문에 TRI_TEST_LOG 테이블에 삽입된 마지막 IDENTITY 값인 7이 반환됩니다.
그리고, 앞의 데이터 삽입 결과에서도 @@IDENTITY 함수의 결과는 TRI_TEST의 마지막 삽입된 IDENTITY 값이 아니라, 트리거에 의하여 삽입된 TRI_TEST_LOG 테이블의 마지막 IDENTTIY 값이 반환된 것입니다.
'DB > MS-SQL' 카테고리의 다른 글
SQL Agent의 작업기록이 남지 않는 문제 (0) | 2010.10.12 |
---|---|
DB 서버 이전을 위한 백업(Backup) / 복구(Restore) 후 연결된 서버 오류(LinkedServerLogin Error) 문제 (0) | 2010.05.11 |
SET IDENTTIY_INSERT 사용시 주의할 점. (0) | 2009.11.26 |
특정 문자열이 포함되어 있는 작업 찾기 (0) | 2009.10.29 |
특정 문자열이 포함되어 있는 저장 프로시저 찾기 (0) | 2009.10.29 |