PostgreSQL에서의 일련번호 처리

PostgreSQL에서의 일련번호 처리


자료 구조를 짤 때, 추상화된 일련 번호를 많이 사용합니다.
이 글은 PostgreSQL에 그 일련 번호 처리를 어떻게 하는지 살펴보는 사용자용 토막글입니다.

시퀀스 개체

PostgreSQL에서는 전통적으로 어떤 숫자를 차례대로 사용할 경우, 시퀀스 SEQUENCE 라는 개체를 사용했습니다.
ioseph=> CREATE SEQUENCE seq;
CREATE SEQUENCE
ioseph=> select nextval('seq');
 nextval
---------
       1
(1개 행)
ioseph=> select nextval('seq');
 nextval
---------
       2
(1개 행)
저렇게 만들고, 저렇게 사용합니다.
응용하면, 테이블을 만들 때, 칼럼의 default 속성에 이것을 사용하면, 기본키가 일련번호인 테이블을 만들 수 있습니다.
ioseph=> CREATE TABLE t (
    pk integer NOT NULL DEFAULT nextval('seq'),
    data text);
CREATE TABLE
ioseph=> INSERT INTO t VALUES (default, 'a');
INSERT 0 1
ioseph=> SELECT * FROM t;
 pk | data
----+------
  3 | a
(1개 행)

SERIAL 자료형

위 시퀀스 개체를 사용하는 경우, 몇 가지 불편한 점이 있습니다. 미리 시퀀스를 만들어야 하며, 테이블을 만들 때, 긴 칼럼 정의를 해야하고, 테이블을 지울 때, 시퀀스도 따로 지워야 합니다. 이런 불편함을 해결 하기 위에서 PostgreSQL에서는 serial 이라는 자료형을 제공합니다.
ioseph=> DROP TABLE t;
DROP TABLE
ioseph=> DROP SEQUENCE seq;
DROP SEQUENCE
ioseph=> CREATE TABLE t (
    pk serial,
    data text);
CREATE TABLE
ioseph=> INSERT INTO t VALUES (default, 'a');
INSERT 0 1
ioseph=> INSERT INTO t VALUES (default, 'a');
INSERT 0 1
ioseph=> SELECT * FROM t;
 pk | data
----+------
  1 | a
  2 | a
(2개 행)
ioseph=> \d t
                            "public.t" 테이블
 필드명 |  종류   | Collation | NULL허용 |            초기값
--------+---------+-----------+----------+-------------------------------
 pk     | integer |           | not null | nextval('t_pk_seq'::regclass)
 data   | text    |           |          |

ioseph=> \ds t_pk_seq
       릴레이션(relation) 목록
 스키마 |   이름   |  종류  | 소유주
--------+----------+--------+--------
 public | t_pk_seq | 시퀀스 | ioseph
(1개 행)

ioseph=> DROP TABLE t;
DROP TABLE
ioseph=> \ds t_pk_seq
"t_pk_seq" 이름을 릴레이션(relation) 없음.
이렇게 독립된 시퀀스 개체를 이용하는 방법보다 간단하고, 테이블 삭제 때 신경 쓸 부분이 적습니다.

GENERATED ALWAYS AS IDENTITY

그런데, 이 serial 자료형을 사용하는 일련 번호 처리는 표준 SQL이 아닙니다. ANSI SQL 2003 규약은 이 일련 번호 처리를 위한 구문으로 
GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY
이런 형태를 사용하자고 제안했습니다.
그래서, PostgreSQL 11 버전부터 이 구문을 지원합니다.
ioseph=> CREATE TABLE t (
    pk integer GENERATED ALWAYS AS IDENTITY,
    data text);
CREATE TABLE
ioseph=> INSERT INTO t VALUES (default, 'a');
INSERT 0 1
ioseph=> INSERT INTO t VALUES (default, 'a');
INSERT 0 1
ioseph=> SELECT * FROM t;
 pk | data
----+------
  1 | a
  2 | a
(2개 행)
위 구문에서 always 와, by default 차이는 스스로 공부하시고.