DB/MS-SQL

@@IDENTITY, SCOPE_IDENTITY(), IDENT_CURRENT() 함수간의 차이점

채윤아빠 2010. 2. 5. 22:26
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 테이블로 로그가 기록되도록 만들었습니다.
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 값이 반환된 것입니다.