한양과학기술고등학교

에듀테크 프로젝트 대시보드

배열 · ENUM · 도메인

text[] ANY unnest ENUM DOMAIN

PostgreSQL 만의 편의 타입들입니다. 남용하면 정규화를 해치니 '값의 작은 집합'에만 쓰세요.

1. 배열

CREATE TABLE posts (id int, tags text[]);
INSERT INTO posts VALUES (1, '{python,fastapi}'), (2, ARRAY['db','sql']);

SELECT * FROM posts WHERE 'sql' = ANY(tags);       -- 요소 포함
SELECT * FROM posts WHERE tags @> ARRAY['db'];      -- 배열 포함
SELECT id, unnest(tags) AS tag FROM posts;          -- 행으로 펼치기
SELECT array_length(tags, 1) FROM posts;            -- 1-based!
-- 배열용 인덱스
CREATE INDEX idx_posts_tags ON posts USING gin (tags);

2. ENUM

CREATE TYPE order_status AS ENUM ('pending', 'paid', 'shipped', 'done');

CREATE TABLE orders (id int, status order_status NOT NULL DEFAULT 'pending');

SELECT * FROM orders WHERE status < 'shipped';   -- 정의된 순서로 비교됨
ALTER TYPE order_status ADD VALUE 'refunded' AFTER 'done';
ENUM 트레이드오프
  • 장점: 저장 4바이트, 정렬 순서 내장, 오타 방지
  • 단점: 값 제거·순서변경 불가(재생성해야 함). 자주 바뀌면 참조 테이블 + FK 가 낫다

3. 도메인

CREATE DOMAIN email AS text
  CHECK (VALUE ~ '^[^@\s]+@[^@\s]+\.[^@\s]+$');

CREATE DOMAIN positive_int AS integer CHECK (VALUE > 0);

CREATE TABLE users (id int, contact email, credits positive_int);

도메인은 '제약이 붙은 타입'입니다. 여러 테이블에서 같은 규칙을 재사용할 때 유용합니다.

4. 언제 정규화로 돌아갈까

배열/JSON 대신 별도 테이블
  • 요소를 independently 조회·수정·카운트해야 할 때
  • 요소에 속성이 붙을 때 (태그에 색상, 생성일 등)
  • 요소가 다른 테이블을 참조(FK)해야 할 때
"인덱스는 공짜가 아니다 — 읽기를 빠르게 하고 쓰기를 느리게 한다"