PostgreSQL에서 Unique Constraints는 상속되지 않는다
PostgreSQL에서 지원하는 재미있는 기능 중에 하나가 바로 테이블 상속(table inheritance)이다. 허나 PostgreSQL의 테이블 상속 기능은 역사적으로 오래되었고, 근근히 유지되는 터라 제한사항이 좀 있으니…
A serious limitation of the inheritance feature is that indexes (including unique constraints) and foreign key constraints only apply to single tables, not to their inheritance children.
아무튼 테이블 상속을 쓰는데 unique constraints가 필요해서 추가했다가, 하위 테이블에는 적용되지 않는 것을 보고 빡쳤다 조금 당황했다. 그래서 매뉴얼을 찾아보니 저렇다더라. 어쨌든 그래도 PostgreSQL은 유연한 ORDBMS다. 원하는 만큼 DB 프로그래밍이 가능하다.
어차피 PostgreSQL에서 컬럼 제약 조건(constraints)이 상속되지 않는다는 것은 unique constraints와 외래 키 참조(foreign key reference) 뿐이고, 일반적인 것은 모두 된다. 그러니까, 직접 만들어서 쓰면 된다는 뜻이다.
CREATE LANGUAGE plpgsql;
CREATE FUNCTION topic_is_unique(an_id bigint, a_name text)
RETURNS boolean AS $$
BEGIN
RETURN (SELECT count(*) FROM topic WHERE name = a_name AND id != an_id LIMIT 1) < 1;
END;
$$ LANGUAGE plpgsql;
CREATE TABLE topic (
id bigserial,
name text NOT NULL CHECK (length(trim(name)) > 0),
CONSTRAINT uniqueness_of_name CHECK (topic_is_unique(id, name))
);
CREATE TABLE person (
nick text NOT NULL CHECK (length(trim(nick)) > 0),
created_at timestamp with time zone DEFAULT (now())
) INHERITS (topic);
topic 테이블에 추가한 uniqueness_of_name 제약 조건은 person 테이블에도 정상적으로 상속된다. 따라서 아래와 같이 의도한대로 작동하게 된다.
dahlia=# INSERT INTO topic (name) VALUES ('~dahlia');
INSERT 0 1
dahlia=# INSERT INTO person (name, nick) VALUES ('~dahlia', 'MinHee');
ERROR: new row for relation "person" violates check constraint "uniqueness_of_name"
dahlia=# INSERT INTO person (name, nick) VALUES ('~someone', 'Someone');
INSERT 0 1
실제로 테이블에는 레코드가 아래와 같이 삽입된다.
dahlia=# SELECT * FROM topic;
id | name
----+----------
1 | ~dahlia
3 | ~someone
(2 rows)
dahlia=# SELECT * FROM person;
id | name | nick | created_at
----+----------+---------+-------------------------------
3 | ~someone | Someone | 2008-11-07 16:49:06.509321+09
(1 row)
