소스: sql-src/mid_11_view_sequence/02_sequence_identity.sql·03_dialects.sql. 시퀀스·IDENTITY 채번과 DB 별 문법 차이를 확인합니다.
CREATE SEQUENCE seq_order START WITH 1000 INCREMENT BY 1 CACHE 20;
SELECT NEXT VALUE FOR seq_order AS next_id;
INSERT INTO orders_seq VALUES (NEXT VALUE FOR seq_order, '김민준', 300);
INSERT INTO orders_seq VALUES (NEXT VALUE FOR seq_order, '박서준', 500);
SELECT
id
, cust
, amt
FROM orders_seq
ORDER BY id;
-- 같은 세션에서 마지막으로 뽑은 값을 다시 확인한다(Oracle 의 CURRVAL 과 같은 역할)
SELECT CURRENT VALUE FOR seq_order AS current_id;ID | CUST | AMT
-----+--------+----
1001 | 김민준 | 300
1002 | 박서준 | 500
(2행)
CURRENT_ID
----------
1002
(1행)NEXT VALUE FOR 는 호출할 때마다 다음 번호를 뽑아 소모합니다. 맨 처음 SELECT 로 1000 을 뽑아 두 INSERT 는 1001·1002 를 받았고, CURRENT VALUE FOR 로 마지막 값을 다시 확인했습니다.
CREATE TABLE members (id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, nm VARCHAR(20));
INSERT INTO members (nm) VALUES ('김철수'), ('이영희');
SELECT
id
, nm
FROM members
ORDER BY id;
-- GENERATED ALWAYS 는 id 값을 직접 지정할 수 없다
-- @error
INSERT INTO members (id, nm) VALUES (100, '직접지정');
-- GENERATED BY DEFAULT 는 값을 생략하면 자동 채번하되 직접 지정도 허용한다
CREATE TABLE members2 (id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, nm VARCHAR(20));
INSERT INTO members2 (nm) VALUES ('김철수');
INSERT INTO members2 (id, nm) VALUES (100, '직접지정');
-- 카운터가 직접 지정한 100 을 기준으로 당겨지지 않아 다음 값은 여전히 2다
INSERT INTO members2 (nm) VALUES ('다음값');
SELECT
id
, nm
FROM members2
ORDER BY id;ID | NM
---+-------
1 | 김철수
2 | 이영희
(2행)
예상 오류: Generated column "PUBLIC.MEMBERS.ID" cannot be assigned
ID | NM
----+---------
1 | 김철수
2 | 다음값
100 | 직접지정
(3행)GENERATED ALWAYS 는 id 값을 직접 지정하면 오류가 나지만, GENERATED BY DEFAULT 는 id = 100 을 직접 넣어도 받아줍니다. 다만 자동 채번 카운터는 그 값을 기준으로 다시 맞춰지지 않아 다음 값이 여전히 2 이므로, 앞으로 카운터가 100 근처까지 올라오면 직접 지정한 값과 충돌할 위험이 있습니다.
SELECT NEXT VALUE FOR seq_order AS before_rollback;
SET AUTOCOMMIT FALSE;
INSERT INTO orders_seq VALUES (NEXT VALUE FOR seq_order, '취소될주문', 100);
ROLLBACK;
-- 롤백된 행은 없지만 방금 뽑은 번호는 이미 소모되어 되돌아오지 않는다
INSERT INTO orders_seq VALUES (NEXT VALUE FOR seq_order, '최도윤', 200);
COMMIT;
SET AUTOCOMMIT TRUE;
SELECT
id
, cust
, amt
FROM orders_seq
ORDER BY id;BEFORE_ROLLBACK
---------------
1003
(1행)
ID | CUST | AMT
-----+--------+----
1001 | 김민준 | 300
1002 | 박서준 | 500
1005 | 최도윤 | 200
(3행)1003(맨 위 조회)과 1004(롤백된 INSERT 에서 소모)는 어느 행에도 남지 않아, 결과는 1002 다음이 곧바로 1005 입니다. 2.7절에서 설명한 구멍이 그대로 재현됩니다.
| DB | 시퀀스·자동 증가 | 세션에서 마지막 값 확인 |
|---|---|---|
| Oracle·Tibero | CREATE SEQUENCE, seq.NEXTVAL |
seq.CURRVAL(NEXTVAL 을 먼저 호출해야 함) |
| MySQL | AUTO_INCREMENT(테이블당 1개, 키 컬럼) |
LAST_INSERT_ID()(세션·연결별) |
| MSSQL | IDENTITY(시작,증가), 2012 부터 SEQUENCE |
SCOPE_IDENTITY()(현재 범위) |
-- Oracle · Tibero
SET MODE Oracle;
CREATE SEQUENCE seq_ora START WITH 500 INCREMENT BY 1;
SELECT seq_ora.NEXTVAL AS next_id FROM DUAL;
-- CURRVAL 은 같은 세션에서 NEXTVAL 을 한 번 호출한 뒤에만 쓸 수 있다
SELECT seq_ora.CURRVAL AS curr_id FROM DUAL;
-- MySQL
SET MODE MySQL;
CREATE TABLE members_my (id INT AUTO_INCREMENT PRIMARY KEY, nm VARCHAR(20));
INSERT INTO members_my (nm) VALUES ('김철수'), ('이영희');
-- 이 커넥션이 마지막으로 만든 자동 증가 값(세션별로 따로 관리)
SELECT LAST_INSERT_ID() AS last_id;NEXT_ID
-------
500
(1행)
CURR_ID
-------
500
(1행)
LAST_ID
-------
2
(1행)Oracle 은 12c 부터 시퀀스 없이도 표준 IDENTITY 컬럼(2.6절)을 바로 쓸 수 있습니다. MySQL 은 SEQUENCE 객체가 따로 없고, MariaDB 는 10.3 부터 지원해 MySQL 과 다릅니다. InnoDB 는 8.0 부터 AUTO_INCREMENT 카운터가 재시작 후에도 유지되며, 그 전 버전은 재시작 때 MAX(id) + 1 로 다시 계산했습니다.
-- MSSQL
SET MODE MSSQLServer;
CREATE TABLE members_ms (id INT IDENTITY(1,1) PRIMARY KEY, nm NVARCHAR(20));
INSERT INTO members_ms (nm) VALUES (N'김철수');
INSERT INTO members_ms (nm) VALUES (N'이영희');
-- 현재 범위(스코프)에서 마지막으로 만든 IDENTITY 값
SELECT SCOPE_IDENTITY() AS scope_id;
-- 2012 부터: SEQUENCE 객체도 함께 쓸 수 있다
CREATE SEQUENCE seq_ms START WITH 1 INCREMENT BY 1;
SELECT NEXT VALUE FOR seq_ms AS next_id;SCOPE_ID
--------
2
(1행)
NEXT_ID
-------
1
(1행)주의MSSQL 은
SCOPE_IDENTITY()말고@@IDENTITY도 있는데, 트리거가 만든 값까지 포함해 현재 세션의 마지막IDENTITY값을 돌려줍니다. 트리거가 다른 테이블에 행을 추가하면 엉뚱한 값이 나올 수 있어 보통SCOPE_IDENTITY()를 씁니다.IDENTITY컬럼에 값을 직접 넣으려면SET IDENTITY_INSERT 테이블 ON을 먼저 실행해야 합니다.@@IDENTITY·SET IDENTITY_INSERT모두 H2 가 지원하지 않아 문법 검토만입니다.