데이터베이스를 설계할 때, 특정 컬럼이나 컬럼 조합이 중복되지 않도록 보장하는 UNIQUE Key 설정은 매우 중요합니다. PostgreSQL에서는 다양한 방법으로 UNIQUE 제약 조건을 설정할 수 있으며, 각 방법마다 사용 목적과 장점이 다릅니다. 이번 글에서는 PostgreSQL에서 UNIQUE Key를 생성하는 모든 방법을 예제와 함께 살펴보겠습니다.
1. UNIQUE 제약 조건 (Constraint) 사용하기
가장 기본적인 방법으로, 테이블을 생성할 때 특정 컬럼에 UNIQUE 제약 조건을 부여하는 방식입니다.
1.1 단일 컬럼에 UNIQUE 설정
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email TEXT UNIQUE
);
위 예제에서는 email 컬럼에 대해 UNIQUE 제약 조건을 설정하여, 중복된 이메일을 허용하지 않습니다.
1.2 다중 컬럼에 UNIQUE 설정 (Composite Key)
CREATE TABLE employees (
id SERIAL PRIMARY KEY,
department TEXT,
email TEXT,
UNIQUE (department, email)
);
department와 email 두 개의 컬럼 조합이 중복되지 않도록 설정합니다. 즉, 같은 부서 내에서는 동일한 이메일이 존재할 수 없지만, 다른 부서에서는 동일한 이메일이 존재할 수 있습니다.
2. ALTER TABLE로 UNIQUE 제약 조건 추가하기
이미 생성된 테이블에 UNIQUE 제약 조건을 추가하려면 ALTER TABLE을 사용합니다.
ALTER TABLE users ADD CONSTRAINT unique_email UNIQUE (email);
기존 테이블의 email 컬럼에 UNIQUE 제약 조건을 추가하는 방식입니다.
3. UNIQUE INDEX 사용하기
PostgreSQL에서는 UNIQUE 제약 조건이 내부적으로 UNIQUE INDEX를 생성하는 방식으로 동작합니다. 따라서 직접 UNIQUE INDEX를 생성하여 UNIQUE를 보장할 수도 있습니다.
CREATE UNIQUE INDEX unique_email_idx ON users (email);
장점:
- 특정 인덱스 옵션을 조정할 수 있음 (예: NULLS NOT DISTINCT)
- 부분 인덱스를 만들 수 있음
- UNIQUE 제약 조건보다 유연함
4. PARTIAL INDEX (부분 인덱스) 사용하기
모든 행에 대해 UNIQUE를 강제하는 것이 아니라, 특정 조건을 만족하는 경우에만 UNIQUE를 적용할 수도 있습니다.
CREATE UNIQUE INDEX unique_active_email_idx
ON users (email)
WHERE is_active = true;
위 인덱스는 is_active = true 조건을 만족하는 데이터만 중복을 방지합니다. 즉, 비활성화된(is_active = false) 계정에서는 중복된 이메일이 존재할 수 있습니다.
5. NULL 값과 UNIQUE
PostgreSQL의 UNIQUE 제약 조건은 NULL 값을 중복으로 간주하지 않습니다. 즉, NULL 값이 여러 개 존재할 수 있습니다.
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name TEXT UNIQUE,
sku TEXT UNIQUE
);
여기서 sku가 NULL인 값이 여러 개 저장될 수 있습니다.
이 동작을 방지하려면 UNIQUE INDEX를 NULLS NOT DISTINCT 옵션과 함께 사용하면 됩니다.
CREATE UNIQUE INDEX unique_sku_idx
ON products (sku)
NULLS NOT DISTINCT;
이렇게 하면 NULL 값도 중복된 것으로 간주되어 하나만 허용됩니다.
6. EXCLUDE 제약 조건 사용하기
PostgreSQL의 EXCLUDE 제약 조건을 사용하면 특정 연산자와 함께 UNIQUE를 적용할 수 있습니다.
CREATE TABLE reservations (
id SERIAL PRIMARY KEY,
room_number INT,
start_time TIMESTAMP,
end_time TIMESTAMP,
EXCLUDE USING GIST (
room_number WITH =,
tstzrange(start_time, end_time) WITH &&
)
);
위 예제는 같은 room_number에 대해 시간이 겹치는 예약을 방지하는 방식입니다.
7. ON CONFLICT를 활용한 중복 방지
PostgreSQL의 INSERT ... ON CONFLICT 문을 사용하면, UNIQUE 제약 조건을 위반하는 경우에 대한 처리를 쉽게 할 수 있습니다.
INSERT INTO users (email) VALUES ('test@example.com')
ON CONFLICT (email) DO NOTHING;
위 코드는 email 값이 이미 존재하면 아무 작업도 수행하지 않습니다.
또는, 기존 데이터를 업데이트하는 방식도 가능합니다.
INSERT INTO users (email, name) VALUES ('test@example.com', 'New Name')
ON CONFLICT (email) DO UPDATE SET name = EXCLUDED.name;
이렇게 하면 email이 이미 존재하는 경우 name 값을 업데이트합니다.
정리
방법 | 사용 예시 | 특징 |
UNIQUE 제약 조건 | CREATE TABLE users (email TEXT UNIQUE); | 가장 기본적인 방법 |
ALTER TABLE | ALTER TABLE users ADD CONSTRAINT unique_email UNIQUE (email); | 기존 테이블에 UNIQUE 추가 |
UNIQUE INDEX | CREATE UNIQUE INDEX unique_email_idx ON users (email); | 인덱스 옵션을 조정할 수 있음 |
PARTIAL INDEX | CREATE UNIQUE INDEX unique_active_email_idx ON users (email) WHERE is_active = true; | 특정 조건에만 UNIQUE 적용 |
NULLS NOT DISTINCT | CREATE UNIQUE INDEX unique_sku_idx ON products (sku) NULLS NOT DISTINCT; | NULL도 중복으로 간주 |
EXCLUDE 제약 조건 | EXCLUDE USING GIST (room_number WITH =, tstzrange(start_time, end_time) WITH &&); | 특정 연산자를 활용한 중복 방지 |
ON CONFLICT | INSERT INTO users ... ON CONFLICT DO UPDATE; | 중복된 경우 예외 처리 |
PostgreSQL에서는 다양한 방법으로 UNIQUE를 적용할 수 있습니다. 제약 조건(Constraint), 인덱스(Index), EXCLUDE 등을 활용하여 데이터의 무결성을 유지하고, 필요에 따라 성능을 최적화하는 것이 중요합니다.
'Develop' 카테고리의 다른 글
SQL INSERT 문에서 싱글 쿼테이션 입력하는 방법 (1) | 2025.02.05 |
---|---|
[PostgreSQL] 순차적으로 증가하는 숫자형 컬럼 중간에 비어있는 값(누락된 값)을 조회 (2) | 2025.02.04 |
TinyMCE 에디터 사용 방법과 이미지 첨부 커스텀마이징 (1) | 2025.01.22 |
[PostgreSQL] SELECT 데이터를 INSERT하는 방법 (2) | 2025.01.22 |
데이터베이스의 개행문자를 HTML에서 줄바꿈으로 표시하는 3가지 방법 (2) | 2025.01.21 |