모든 강의를 무료로 볼 수 있어요. 회원가입 없이도 학습 가능합니다.

21강 / 전체 24강

제약 조건

8분 읽기 조회 0

PRIMARY KEY·FOREIGN KEY·UNIQUE·NOT NULL·CHECK·DEFAULT 제약 조건으로 잘못된 데이터가 DB에 들어오는 것을 원천 차단합니다.

🎯 학습 목표

이 강을 마치면 테이블 설계 시 데이터 무결성을 보장하는 6가지 제약 조건(PRIMARY KEY, FOREIGN KEY, UNIQUE, NOT NULL, CHECK, DEFAULT)을 올바르게 적용할 수 있습니다. 각 제약이 어떤 잘못된 데이터를 막는지, 그리고 외래키가 테이블 간 참조 무결성을 어떻게 보호하는지 이해할 수 있게 됩니다.

💡 제약 조건이 필요한 이유

이 섹션에서는 애플리케이션 코드 대신 DB 수준에서 데이터를 검증해야 하는 이유를 살펴보겠습니다.

애플리케이션(Python 코드, 웹 서버 등)에서 유효성 검사를 해도 DB에 직접 SQL을 실행하면 우회할 수 있습니다. 또한 여러 애플리케이션이 같은 DB를 사용할 때 모든 곳에서 동일한 검증 로직을 유지하기 어렵습니다. 제약 조건(Constraint)은 DB 수준에서 데이터 규칙을 강제해, 어떤 경로로 데이터가 들어오더라도 규칙을 위반하면 거부합니다.

예를 들어 orders.member_id가 존재하지 않는 회원을 가리키는 경우(참조 무결성 위반), 이메일 열에 같은 주소가 두 번 들어가는 경우(유일성 위반), 수량에 -1이 입력되는 경우(비즈니스 규칙 위반)를 모두 DB가 자동으로 막아줍니다.

🔑 PRIMARY KEY — 기본키

이 섹션에서는 행을 고유하게 식별하는 기본키(PRIMARY KEY) 제약을 살펴보겠습니다.

PRIMARY KEY는 테이블의 각 행을 유일하게 식별하는 열(또는 열 조합)입니다. 기본키에는 자동으로 두 가지 제약이 적용됩니다. 첫째로 UNIQUE(중복 불가), 둘째로 NOT NULL(NULL 불가)입니다.

-- 단일 열 기본키
CREATE TABLE products (
  product_id  INTEGER  PRIMARY KEY,
  name        TEXT     NOT NULL
);

-- 복합 기본키 (두 열의 조합이 고유해야 함)
CREATE TABLE order_items (
  order_id    INTEGER,
  item_seq    INTEGER,
  product_id  INTEGER  NOT NULL,
  quantity    INTEGER  NOT NULL DEFAULT 1,
  PRIMARY KEY (order_id, item_seq)  -- 테이블 수준 제약
);

SQLite에서 INTEGER PRIMARY KEY는 특별히 SQLite의 내부 rowid와 연결되어 AUTOINCREMENT 없이도 자동 증가하는 정수를 할당받습니다. 반면 TEXT PRIMARY KEY는 자동 증가가 없고 직접 값을 지정해야 합니다.

🔗 FOREIGN KEY — 외래키

이 섹션에서는 테이블 간 참조 무결성을 보장하는 외래키 제약을 살펴보겠습니다.

FOREIGN KEY는 다른 테이블의 기본키를 참조하는 열에 붙여, 참조하는 행이 반드시 존재하도록 강제합니다. 12강에서 개념으로 배웠던 외래키를 이제 실제 제약으로 정의합니다.

CREATE TABLE orders_with_fk (
  order_id   INTEGER  PRIMARY KEY AUTOINCREMENT,
  member_id  INTEGER  NOT NULL,
  book_id    INTEGER  NOT NULL,
  quantity   INTEGER  NOT NULL DEFAULT 1,
  order_date TEXT     NOT NULL DEFAULT (date('now')),
  status     TEXT     NOT NULL DEFAULT 'PENDING',
  FOREIGN KEY (member_id) REFERENCES members(member_id)
    ON DELETE RESTRICT   -- 회원 삭제 시 주문 있으면 거부
    ON UPDATE CASCADE,   -- 회원 ID 변경 시 주문의 member_id도 함께 변경
  FOREIGN KEY (book_id) REFERENCES books(book_id)
    ON DELETE RESTRICT
);

ON DELETE와 ON UPDATE는 참조하는 행이 삭제되거나 기본키가 변경될 때 어떻게 처리할지 정의합니다.

옵션설명
RESTRICT (기본값)참조하는 행이 있으면 삭제·수정 거부
CASCADE참조하는 행도 함께 삭제·수정
SET NULL참조하는 행의 외래키를 NULL로 설정
NO ACTION즉시는 허용, 트랜잭션 종료 시 체크

⚠️ SQLite에서 외래키 제약은 기본적으로 비활성화되어 있습니다. 활성화하려면 연결할 때마다 PRAGMA foreign_keys = ON;을 실행해야 합니다. MySQL, PostgreSQL은 기본으로 활성화되어 있습니다.

-- SQLite에서 외래키 활성화
PRAGMA foreign_keys = ON;

-- 이제 참조 무결성 위반 시 오류 발생
INSERT INTO orders_with_fk (member_id, book_id)
VALUES (999, 1);  -- 오류: member_id 999는 members에 없음

🔒 UNIQUE, NOT NULL, CHECK, DEFAULT

이 섹션에서는 나머지 네 가지 제약 조건을 살펴보겠습니다.

UNIQUE는 열의 모든 값이 고유해야 합니다. 기본키와 달리 NULL을 허용하고(NULL은 서로 다른 값으로 취급), 테이블에 여러 UNIQUE 제약을 가질 수 있습니다.

CREATE TABLE users (
  user_id  INTEGER  PRIMARY KEY,
  email    TEXT     NOT NULL UNIQUE,  -- 이메일 중복 불가
  username TEXT     NOT NULL UNIQUE   -- 닉네임 중복 불가
);

NOT NULL은 해당 열에 NULL 값을 허용하지 않습니다. 필수 입력 필드에 사용합니다.

CHECK는 열 값이 특정 조건을 만족해야 합니다. 애플리케이션 수준의 유효성 검사를 DB 수준으로 내립니다.

CREATE TABLE products (
  product_id  INTEGER  PRIMARY KEY,
  name        TEXT     NOT NULL,
  price       INTEGER  NOT NULL CHECK(price > 0),          -- 가격은 양수
  stock       INTEGER  NOT NULL DEFAULT 0 CHECK(stock >= 0), -- 재고는 0 이상
  category    TEXT     CHECK(category IN ('A', 'B', 'C'))  -- 허용 카테고리만
);

CHECK 제약을 위반하는 INSERT나 UPDATE를 시도하면 즉시 오류가 발생합니다.

DEFAULT는 INSERT 시 값을 생략하면 지정한 기본값이 자동으로 입력됩니다. 상수 값이나 함수(date('now'), datetime('now') 등)를 사용할 수 있습니다.

-- 세 가지 제약을 조합한 완성형 테이블
CREATE TABLE review (
  review_id   INTEGER  PRIMARY KEY AUTOINCREMENT,
  member_id   INTEGER  NOT NULL,
  book_id     INTEGER  NOT NULL,
  rating      INTEGER  NOT NULL CHECK(rating BETWEEN 1 AND 5),
  content     TEXT,
  created_at  TEXT     NOT NULL DEFAULT (datetime('now')),
  FOREIGN KEY (member_id) REFERENCES members(member_id) ON DELETE CASCADE,
  FOREIGN KEY (book_id)   REFERENCES books(book_id)     ON DELETE CASCADE,
  UNIQUE (member_id, book_id)  -- 한 회원이 같은 도서에 리뷰 하나만
);

review_id는 자동 증가 기본키, rating은 1~5 사이만 허용, created_at은 현재 시각 자동 입력, 같은 (회원, 도서) 조합의 리뷰는 한 개만 허용(UNIQUE 복합 제약), 회원이나 도서가 삭제되면 리뷰도 함께 삭제(CASCADE)하는 완성도 높은 테이블입니다.

📝 핵심 요약

이번 강에서 배운 내용을 정리하겠습니다.

제약역할NULL 허용
PRIMARY KEY행 고유 식별 (UNIQUE + NOT NULL)불가
FOREIGN KEY다른 테이블 PK 참조 무결성가능 (기본)
UNIQUE열 값 중복 불가가능 (NULL끼리는 별개)
NOT NULLNULL 값 금지불가
CHECK(조건)값이 조건을 만족해야 함NULL은 체크 통과
DEFAULT 값값 생략 시 기본값 자동 입력—

제약 조건은 데이터 품질을 코드가 아닌 DB가 보장하는 핵심 메커니즘입니다. 다음 22강에서는 대용량 데이터에서 조회 속도를 극적으로 높이는 인덱스를 배웁니다. 언제 인덱스가 효과적인지, 인덱스의 부작용은 무엇인지 이해하게 됩니다.

관련 주제

  • PRIMARY KEY
  • FOREIGN KEY
  • UNIQUE
  • NOT NULL
  • CHECK
  • DEFAULT
  • 참조 무결성
  • 데이터 무결성
  • 개발·프로그래밍
  • 개발·프로그래밍 강의
  • SQL·데이터베이스 입문 24강
  • 무료강의
  • 무료 온라인 강의
  • NUGUNA
  • 누구나

📚 시리즈 전체 공유

SQL·데이터베이스 입문 24강

이 강의가 속한 시리즈는 총 24강, 모두 무료입니다. 처음부터 배우려는 동료에게 시리즈 전체를 알려 주세요.

댓글

0/1000

불러오는 중...