2.3Database-Side Validation and Constraints
데이터 단위 제약을 설정해 데이터 무결성 보장하기
TL;DR
Row-Level Validation: 데이터 단위 제약 설정하기
PostgreSQL에서는 행(row) 단위로 유효성 검사를 할 수 있는 다양한 방법이 제공된다. 이를 통해 잘못된 데이터가 들어오는 것을 근본적으로 차단할 수 있다.
예시 테이블 구조
sqlCREATE TABLE products ( id SERIAL PRIMARY KEY, name VARCHAR(40), department VARCHAR(40), price INTEGER, weight INTEGER )
1. NOT NULL 제약
값이 반드시 있어야 하는 열(예: ID, 값 등)에 NOT NULL
제약을 건다.
테이블 생성 시
sqlprice INTEGER NOT NULL //....
테이블 생성 후 적용
sqlALTER TABLE products ALTER COLUMN price SET NOT NULL;
- 만약 이미
NULL
값이 있으면 에러가 뜬다. - 이럴 때는 기존 데이터를 먼저 수정한 후 적용한다.
sqlUPDATE products SET price = 9 WHERE price IS NULL -- WHERE price = NULL 아님!
2. 기본값 설정(DEFAULT)
값을 명시하지 않았을 때 자동으로 들어갈 기본값을 설정할 수 있다.
테이블 생성 시
sqlprice INTEGER DEFAULT 9
테이블 생성 후 적용
sqlALTER TABLE products ALTER COLUMN price SET DEFAULT 9;
- 기본값은
INSERT
시 값을 생략하면 자동 적용된다. - 기본값은 언제든 변경 가능하다.
3. 고유값 제한(UNIQUE)
특정 컬럼에 중복된 값이 들어가지 않도록 한다.
테이블 생성 시
sqlname VARCHAR(50) UNIQUE
테이블 생성 후 적용
sqlALTER TABLE products ADD UNIQUE(name);
4. 여러 컬럼 조합에 대한 UNIQUE
두 개 이상의 컬럼 조합이 고유해야 하는 경우도 있다.
sqlALTER TABLE products ADD UNIQUE (name, department);
기존 제약 제거
기존의 constraint를 없애려면, Schemas/Public/Tables에서 만들어둔 테이블로 들어간다. Constraints 섹션에서 없애려는 constraint 이름을 찾아 우클릭을 해 Query Tool 메뉴를 눌러 쿼리 툴로 들어가, 아래의 쿼리를 입력한다.
sqlALTER TABLE products DROP CONSTRAINT products_name_key;
5. 값에 유효성 검사 조건 걸기(CHECK)
아래와 같은 경우는 잘못된 데이터(음수 가격)이므로 추가되면 안된다.
sqlINSERT INTO products (name, department, price, weight) VALUES ('Belt', 'Clothes', -99, 1);
이런 경우 ADD CHECK
로 체크 조건문을 추가하는데, 체크는 우리가 추가/업데이트 하는 row에만 적용된다.
sqlALTER TABLE products ADD CHECK (price > 0);
6. 컬럼 간에 Validation Check 추가하기
아래와 같이 주문 내역을 관리하는 테이블을 만든다고 하자.
sqlCREATE TABLE orders ( id SERIAL PRIMARY KEY, name VARCHAR(40) NOT NULL, created_at TIMESTAMP NOT NULL, est_delivery TIMESTAMP NOT NULL, CHECK (created_at < est_delivery) );
이 테이블의 경우, 예상 배송 시간(estimated delivery)이 주문 생성 시간(created_at)보다 항상 뒤여야 함을 체크로 지정한 것이다. 이렇게 체크를 걸어두면, 아래의 예시는 에러를 발생시킨다.
sqlINSERT INTO orders (name, created_at, est_delivery) VALUES ('Shirt', '2000-NOV-20 01:00AM'::TIMESTAMP, '2000-NOV-10 01:00AM');
7. Validation은 어디에 적용해야할까?
유저 -> 웹 서버 -> 데이터베이스로 이어지는 플로우에서 어디에 Validation을 적용해야 할까?
웹 서버에서 유효성 검사
- 장점:
- 사용자마다 다른 조건 처리 가능
- 복잡한 비즈니스 로직 처리 가능
- 대부분의 프로그래밍 언어가 타입 기반 유효성 검사 지원
- 단점:
- 클라이언트가 우회하면 잘못된 데이터가 들어갈 수도 있음
데이터베이스에서 유효성 검사
- 장점:
- 모든 경로에서 데이터 무결성을 강제할 수 있음(API든 SQL이든)
- 핵심적인 데이터 규칙을 데이터베이스에 직접 명시 가능
- 단점:
- 제약 추가가 어렵다(기존 모든 행이 조건을 만족해야 한다)
- 예:
NOT NULL
을 추가하려면 기존 데이터의 모든 행이 NULL이 아니어야만 가능하다
- 예:
- 사용자마다 다른 조건을 넣는 등의 유연한 로직 구현은 어렵다
- 제약 추가가 어렵다(기존 모든 행이 조건을 만족해야 한다)
이런 차이 때문에 보통은 데이터베이스에 기본적이고 중요한 체크들(예: 가격은 0보다 커야한다)을 적용하고 다른 동적이고 복잡한 유효성 검사들(예: 회원 등급별 구매 제한, 유저별 조건 차등 처리)은 웹 서버에 적용한다.