icon

안동민 개발노트

7장 : 데이터 모델링과 ERD

ER 모델을 릴레이션으로 변환


ERD를 설계했으면 이제 실제 테이블로 변환해야 합니다. 개념적 모델의 개체·관계·속성을 릴레이션 스키마로 바꾸는 일정한 규칙이 있습니다. 이 절에서는 7가지 변환 규칙을 하나씩 적용하며, 쇼핑몰과 학사 관리 시스템을 완전한 SQL DDL로 구현합니다.


변환 규칙 전체 흐름

ER → 릴레이션 변환 7단계
┌──────────────────────────────────────────────────────────┐
│              ER → 릴레이션 변환 순서                     │
├──────────────────────────────────────────────────────────┤
│                                                          │
│  1단계: 강한 개체(Strong Entity) → 테이블                │
│  2단계: 약한 개체(Weak Entity) → 테이블                  │
│  3단계: 1:1 관계 → FK 배치                               │
│  4단계: 1:N 관계 → N쪽에 FK                              │
│  5단계: M:N 관계 → 교차 테이블                           │
│  6단계: 다중값 속성 → 별도 테이블                        │
│  7단계: 복합 속성 / 파생 속성 처리                       │
│                                                          │
│  ※ 순서가 중요: 강한 개체부터 만들어야                   │
│    FK 참조 대상이 존재                                   │
│                                                          │
└──────────────────────────────────────────────────────────┘

1단계: 강한 개체의 변환

강한 개체는 그대로 하나의 테이블이 됩니다. 키 속성은 기본키(PK)가 되고, 나머지 속성은 컬럼이 됩니다.

변환 규칙
강한 개체 → 테이블
  * 개체명 → 테이블명
  * 키 속성 → PRIMARY KEY
  * 단순 속성 → 일반 컬럼
  * 복합 속성 → 하위 속성들을 개별 컬럼
  * 파생 속성 → 저장하지 않거나 별도 컬럼(반정규화)
예시: 회원 개체 변환
ER 모델
  개체: 회원
  속성: 회원번호(PK), 이름, 이메일, 가입일

     ↓ 변환

릴레이션
  users (
    id         NUMBER       PRIMARY KEY,
    name       VARCHAR2(50) NOT NULL,
    email      VARCHAR2(100) UNIQUE,
    created_at DATE         DEFAULT SYSDATE
  )
예시: 상품 개체 변환
ER 모델
  개체: 상품
  속성: 상품번호(PK), 상품명, 가격, 재고수량

     ↓ 변환

릴레이션
  products (
    id    NUMBER        PRIMARY KEY,
    name  VARCHAR2(200) NOT NULL,
    price NUMBER(10,2)  NOT NULL CHECK (price >= 0),
    stock NUMBER        DEFAULT 0 CHECK (stock >= 0)
  )

강한 개체 변환 시 주의할 점입니다.

강한 개체 변환 시 고려사항
1. PK 전략
   * 자연키 (학번, 주민번호 등) → ER 모델의 키 속성 그대로
   * 대리키 (일련번호) → 실무에서 선호
   * 복합키 → 2개 이상 속성으로 구성된 키

2. NOT NULL 판단
   * 필수 속성 → NOT NULL
   * 선택 속성 → NULL 허용
   * ER 모델의 참여 제약 참고

3. 도메인 제약
   * 가격 ≥ 0, 수량 ≥ 0 등 CHECK 제약
   * 이메일 형식 등 패턴 제약
   * UNIQUE 제약 (후보키)

4. 네이밍 규칙
   * 개체명: 단수 → 테이블명: 복수 (관례)
   * 속성명: snake_case 통일 (실무 표준)

2단계: 약한 개체의 변환

약한 개체는 소유 개체의 기본키를 외래키(FK)로 포함하고, 부분 키(Partial Key)와 합쳐서 복합 기본키를 만듭니다.

약한 개체 변환 규칙
약한 개체 → 테이블
  * 소유 개체의 PK → FK + PK의 일부
  * 부분 키 → PK의 나머지 부분
  * 결과 PK = {소유 개체 PK, 부분 키}
  * 식별 관계(Identifying Relationship) 통해 연결
예시: 주문 → 주문상세 (약한 개체)
ER 모델
  주문(Order) ──식별관계──→ 주문상세(OrderItem, 약한 개체)
  OrderItem의 부분 키: item_seq

     ↓ 변환

릴레이션
  order_items (
    order_id  NUMBER  REFERENCES orders(id),
    item_seq  NUMBER,
    product_id NUMBER NOT NULL,
    quantity   NUMBER NOT NULL,
    price      NUMBER(10,2) NOT NULL,
    PRIMARY KEY (order_id, item_seq)
  )
예시: 건물 → 강의실 (약한 개체)
ER 모델
  건물(Building) ──식별관계──→ 강의실(Room, 약한 개체)
  Room의 부분 키: room_number

     ↓ 변환

릴레이션
  buildings (
    id    NUMBER PRIMARY KEY,
    name  VARCHAR2(50) NOT NULL,
    addr  VARCHAR2(200)
  )

  rooms (
    building_id  NUMBER REFERENCES buildings(id),
    room_number  VARCHAR2(10),
    capacity     NUMBER,
    has_projector CHAR(1) DEFAULT 'N',
    PRIMARY KEY (building_id, room_number)
  )
실무에서의 대리키 사용
복합 기본키 vs 대리키

복합키 방식
  order_items (
    order_id  NUMBER,
    item_seq  NUMBER,
    ...
    PRIMARY KEY (order_id, item_seq)
  )

대리키 방식 (실무에서 더 흔함)
  order_items (
    id        NUMBER PRIMARY KEY,  ← 대리키
    order_id  NUMBER NOT NULL REFERENCES orders(id),
    ...
    UNIQUE (order_id, item_seq)    ← 유일성은 UNIQUE로
  )

대리키를 사용하는 이유
  * ORM(JPA, TypeORM 등)과의 호환성
  * FK 참조 시 조인 컬럼이 단일 → 쿼리 단순화
  * 키 변경 시 영향 범위 감소
  * 단, 이론적 정석은 복합키

3단계: 1:1 관계의 변환

1:1 관계는 세 가지 방법으로 변환할 수 있습니다.

1:1 관계 변환 — 3가지 방법
방법 1: 한쪽 테이블에 FK 추가 (가장 일반적)
  * 전체 참여 쪽에 FK를 놓는 것이 유리
  * FK + UNIQUE 제약으로 1:1 보장

  회원(user_id PK) ── 1:1 ── 프로필(profile)

  users    (id, name, email)
  profiles (id PK, user_id FK UNIQUE, bio, avatar)
  → user_id에 UNIQUE 제약 = 1:1 보장

방법 2: 양쪽 테이블 병합
  * 두 개체를 하나의 테이블로 통합
  * 속성이 적거나 항상 함께 사용될 때

  users (id, name, email, bio, avatar)
  → 프로필 속성을 users에 직접 포함

방법 3: 관계 테이블 생성 (거의 사용 안 함)
  * 양쪽 PK를 FK로 갖는 별도 테이블
  * 관계에 속성이 많거나 선택적 참여일 때

  user_profiles (user_id FK UNIQUE, profile_id FK UNIQUE, created_at)
1:1 변환 시 FK 배치 기준
┌──────────────────────────────────────────────────┐
│  FK를 어디에 놓을 것인가?                        │
├──────────────────────────────────────────────────┤
│                                                  │
│  원칙: 전체 참여(Total Participation) 쪽에 FK    │
│                                                  │
│  사원 ─(1:1)─ 주차공간                           │
│  사원: 주차공간이 없을 수도 (부분 참여)          │
│  주차공간: 반드시 사원에게 배정 (전체 참여)      │
│                                                  │
│  → 주차공간 테이블에 employee_id FK              │
│  → NULL이 발생하지 않아 공간 낭비 없음           │
│                                                  │
│  양쪽 모두 부분 참여이면:                        │
│  → 어느 쪽이든 가능, 접근 빈도가 높은 쪽 선택    │
│                                                  │
└──────────────────────────────────────────────────┘

4단계: 1:N 관계의 변환

1:N 관계는 가장 흔한 관계이며, 변환 규칙도 가장 단순합니다.

1:N 관계 변환 규칙
N쪽 테이블에 1쪽의 PK를 FK로 추가

  부서(1) ──(1:N)── 직원(N)

  departments (id PK, name, location)
  employees   (id PK, dept_id FK, name, hire_date)
  → dept_id가 departments.id를 참조
관계에 속성이 있는 1:N
ER 모델
  교수(1) ──(1:N)── 과목(N)
  관계 속성: 담당학기, 강의실

변환 방법 1: N쪽에 관계 속성도 포함
  courses (
    id        NUMBER PRIMARY KEY,
    prof_id   NUMBER REFERENCES professors(id),
    name      VARCHAR2(100),
    semester  VARCHAR2(10),    ← 관계 속성
    room      VARCHAR2(20)     ← 관계 속성
  )

변환 방법 2: 별도 테이블 (관계 속성이 많을 때)
  course_assignments (
    prof_id  NUMBER REFERENCES professors(id),
    course_id NUMBER REFERENCES courses(id),
    semester VARCHAR2(10),
    room     VARCHAR2(20),
    PRIMARY KEY (prof_id, course_id, semester)
  )
자기참조 1:N 관계
ER 모델
  사원(1) ──관리──→ 사원(N)
  (상사 1명이 부하 직원 N명을 관리)

변환
  employees (
    id          NUMBER PRIMARY KEY,
    name        VARCHAR2(50),
    manager_id  NUMBER REFERENCES employees(id)
  )

  → 최상위 관리자의 manager_id = NULL

SQL 조회
  -- 김부장의 직속 부하
  SELECT e.name
  FROM employees e
  WHERE e.manager_id = (
    SELECT id FROM employees WHERE name = '김부장'
  );

5단계: M:N 관계의 변환

M:N 관계는 반드시 교차 테이블(Junction Table)을 생성하여 해소합니다.

M:N 관계 변환 규칙
양쪽 개체의 PK를 FK로 포함하는 새 테이블 생성
  * 관계 속성이 있으면 교차 테이블의 컬럼으로 추가
  * PK = 양쪽 FK의 복합 (또는 대리키)
예시: 학생-과목 M:N
ER 모델
  학생 ──M:N──→ 과목 (수강 관계, 관계 속성: 학점, 수강년도)

     ↓ 변환

students (
  id   NUMBER PRIMARY KEY,
  name VARCHAR2(50) NOT NULL
)

courses (
  id     NUMBER PRIMARY KEY,
  title  VARCHAR2(100) NOT NULL,
  credit NUMBER NOT NULL
)

enrollments (                       ← 교차 테이블
  student_id NUMBER REFERENCES students(id),
  course_id  NUMBER REFERENCES courses(id),
  grade      VARCHAR2(2),           ← 관계 속성
  year       NUMBER,                ← 관계 속성
  semester   VARCHAR2(10),
  PRIMARY KEY (student_id, course_id, year, semester)
)
예시: 자기참조 M:N (SNS 팔로우)
ER 모델
  사용자 ──M:N──→ 사용자 (팔로우 관계)

     ↓ 변환

users (
  id       NUMBER PRIMARY KEY,
  username VARCHAR2(50) UNIQUE
)

follows (                              ← 교차 테이블
  follower_id  NUMBER REFERENCES users(id),
  following_id NUMBER REFERENCES users(id),
  created_at   DATE DEFAULT SYSDATE,
  PRIMARY KEY (follower_id, following_id),
  CHECK (follower_id != following_id)  ← 자기 팔로우 방지
)
M:N 교차 테이블 네이밍 관례
양쪽 테이블명을 조합하거나 관계명을 사용

  students + courses    → enrollments (관계명)
  users + users         → follows     (관계명)
  posts + tags          → post_tags   (양쪽 조합)
  users + roles         → user_roles  (양쪽 조합)
  orders + products     → order_items (관계명)

네이밍 원칙
  * 관계에 의미가 있으면 관계명 사용 (enrollments, follows)
  * 단순 연결이면 양쪽 조합 (post_tags, user_roles)
  * 알파벳 순서로 조합하는 관례도 있음

6단계: 다중값 속성의 변환

다중값 속성(Multi-valued Attribute)은 별도의 테이블로 분리합니다.

다중값 속성 변환 규칙
다중값 속성 → 새 테이블
  * 원래 개체의 PK를 FK로 포함
  * 다중값 속성을 일반 컬럼으로
  * PK = {FK, 속성값} 또는 대리키
예시: 전화번호 (다중값)
ER 모델
  회원 ── 전화번호 (다중값: 집, 회사, 휴대폰)

     ↓ 변환

users (id, name, email)

user_phones (
  user_id  NUMBER REFERENCES users(id),
  phone    VARCHAR2(20) NOT NULL,
  type     VARCHAR2(10),          ← '집', '회사', '휴대폰'
  PRIMARY KEY (user_id, phone)
)
예시: 취미 (다중값)
ER 모델
  사원 ── 취미 (다중값)

     ↓ 변환

employees (id, name, dept_id)

employee_hobbies (
  employee_id NUMBER REFERENCES employees(id),
  hobby       VARCHAR2(50) NOT NULL,
  PRIMARY KEY (employee_id, hobby)
)

7단계: 복합 속성과 파생 속성

복합 속성은 하위 속성들을 개별 컬럼으로 분해합니다.

복합 속성 변환
ER 모델
  주소 = { 시, 구, 동, 상세주소, 우편번호 }

     ↓ 변환

users (
  id,
  name,
  addr_city     VARCHAR2(50),
  addr_district VARCHAR2(50),
  addr_dong     VARCHAR2(50),
  addr_detail   VARCHAR2(200),
  addr_zipcode  VARCHAR2(10)
)

파생 속성(Derived Attribute)은 다른 속성에서 계산되는 값입니다.

파생 속성 처리 판단
파생 속성 예시
  * 나이 ← 생년월일에서 계산
  * 주문총액 ← SUM(수량 * 단가)
  * 재직기간 ← CURRENT_DATE - 입사일

처리 방법
┌──────────────────────────────────────────────────┐
│ 방법 1: 저장하지 않음 (정규화 원칙)              │
│   * 조회 시 매번 계산                            │
│   * SELECT EXTRACT(YEAR FROM AGE(birth_date))    │
│     AS age FROM users;                           │
│   * 장점: 항상 최신 값, 갱신 이상 없음           │
│   * 단점: 계산 비용                              │
│                                                  │
│ 방법 2: 저장 (반정규화)                          │
│   * 컬럼으로 추가하되 일관성 유지 필요           │
│   * orders.total_amount = SUM(items.qty * price) │
│   * 장점: 조회 성능                              │
│   * 단점: 갱신 시 동기화 필요 (트리거/배치)      │
│                                                  │
│ 방법 3: 가상 컬럼 / 계산 컬럼 (DBMS 기능)        │
│   * Oracle: GENERATED ALWAYS AS (expr)           │
│   * MySQL: AS (expr) STORED / VIRTUAL            │
│   * PostgreSQL: Generated Column                 │
│   * 장점: 자동 계산, 인덱싱 가능                 │
│                                                  │
└──────────────────────────────────────────────────┘

상속(일반화/특수화) 관계의 변환

ER 모델에서 포괄·부분 관계(ISA 관계, Generalization/Specialization)를 변환하는 3가지 전략이 있습니다.

예시: 사용자 상속 구조
ER 모델
           사용자(User)
          /       |      \
학생(Student) 교수(Prof) 직원(Staff)
전략 1: 단일 테이블 전략 (Single Table)
users (
  id          NUMBER PRIMARY KEY,
  type        VARCHAR2(10) NOT NULL,  ← 구분자
  name        VARCHAR2(50),
  -- 학생 속성
  student_id  VARCHAR2(20),
  gpa         NUMBER(3,2),
  -- 교수 속성
  prof_id     VARCHAR2(20),
  department  VARCHAR2(50),
  -- 직원 속성
  staff_id    VARCHAR2(20),
  position    VARCHAR2(50)
)

장점: 조인 없이 조회, 단순한 구조
단점: NULL이 많아짐, 테이블이 비대해짐
적용: 하위 타입 속성이 적을 때
전략 2: 각 타입별 테이블 (Table per Type)
users (
  id    NUMBER PRIMARY KEY,
  name  VARCHAR2(50)
)

students (
  user_id    NUMBER PRIMARY KEY REFERENCES users(id),
  student_id VARCHAR2(20),
  gpa        NUMBER(3,2)
)

professors (
  user_id    NUMBER PRIMARY KEY REFERENCES users(id),
  prof_id    VARCHAR2(20),
  department VARCHAR2(50)
)

장점: NULL 없음, 정규화된 구조
단점: 조회 시 조인 필요
적용: 공통 속성이 많고 타입별 속성도 많을 때
전략 3: 구체 테이블 전략 (Table per Concrete)
students (
  id          NUMBER PRIMARY KEY,
  name        VARCHAR2(50),       ← 공통 속성 반복
  student_id  VARCHAR2(20),
  gpa         NUMBER(3,2)
)

professors (
  id          NUMBER PRIMARY KEY,
  name        VARCHAR2(50),       ← 공통 속성 반복
  prof_id     VARCHAR2(20),
  department  VARCHAR2(50)
)

장점: 조인 불필요, 타입별 독립적
단점: 공통 속성 중복, 전체 사용자 조회 시 UNION 필요
적용: 타입 간 공통점이 적을 때
상속 변환 전략 비교
┌──────────────┬──────────────┬──────────────┬───────────────┐
│     항목     │ 단일 테이블  │ 타입별 테이블│ 구체 테이블   │
├──────────────┼──────────────┼──────────────┼───────────────┤
│ NULL 발생    │     많음     │     없음     │     없음      │
│ 조인 필요    │     없음     │     있음     │     없음      │
│ 공통 속성    │    한 곳     │    한 곳     │     반복      │
│ 타입 추가    │ 컬럼 추가    │ 테이블 추가  │ 테이블 추가   │
│ 전체 조회    │     단순     │     조인     │ UNION         │
│ 타입별 조회  │ WHERE 필터   │     단순     │     단순      │
│ ORM 지원     │ 기본 전략    │ JPA JOINED   │ JPA TABLE_PER │
└──────────────┴──────────────┴──────────────┴───────────────┘

실습 — 쇼핑몰 ERD를 SQL로 변환

앞 절에서 설계한 쇼핑몰 ERD를 Oracle SQL로 구현합니다.

쇼핑몰 스키마 생성 (Oracle)
-- 1단계: 강한 개체 변환
CREATE TABLE categories (
    id        NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    name      VARCHAR2(100) NOT NULL,
    parent_id NUMBER REFERENCES categories(id)
);

CREATE TABLE users (
    id         NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    name       VARCHAR2(50)  NOT NULL,
    email      VARCHAR2(100) NOT NULL UNIQUE,
    phone      VARCHAR2(20),
    address    VARCHAR2(300),
    created_at DATE DEFAULT SYSDATE
);

-- 4단계: 1:N 관계 (카테고리-상품)
CREATE TABLE products (
    id          NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    category_id NUMBER NOT NULL REFERENCES categories(id),
    name        VARCHAR2(200) NOT NULL,
    price       NUMBER(10, 2) NOT NULL CHECK (price >= 0),
    stock       NUMBER DEFAULT 0 CHECK (stock >= 0)
);

-- 4단계: 1:N 관계 (회원-주문)
CREATE TABLE orders (
    id          NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    user_id     NUMBER NOT NULL REFERENCES users(id),
    order_date  DATE DEFAULT SYSDATE,
    status      VARCHAR2(20) DEFAULT 'pending',
    total_amount NUMBER(12, 2)
);

-- 2단계: 약한 개체 변환 (주문-주문상세)
CREATE TABLE order_items (
    id         NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    order_id   NUMBER NOT NULL REFERENCES orders(id)
               ON DELETE CASCADE,
    product_id NUMBER NOT NULL REFERENCES products(id),
    quantity   NUMBER NOT NULL CHECK (quantity > 0),
    unit_price NUMBER(10, 2) NOT NULL
);

-- 추가 개체: 리뷰
CREATE TABLE reviews (
    id         NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    user_id    NUMBER NOT NULL REFERENCES users(id),
    product_id NUMBER NOT NULL REFERENCES products(id),
    rating     NUMBER(1) CHECK (rating BETWEEN 1 AND 5),
    content    VARCHAR2(2000),
    created_at DATE DEFAULT SYSDATE
);

-- 3단계: 1:1 관계 (주문-배송)
CREATE TABLE shipping (
    id          NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    order_id    NUMBER NOT NULL UNIQUE REFERENCES orders(id),
    status      VARCHAR2(20) DEFAULT 'preparing',
    tracking_no VARCHAR2(50),
    carrier     VARCHAR2(50),
    shipped_at  DATE
);
쇼핑몰 스키마 (MySQL 버전)
CREATE TABLE categories (
    id        INT AUTO_INCREMENT PRIMARY KEY,
    name      VARCHAR(100) NOT NULL,
    parent_id INT,
    FOREIGN KEY (parent_id) REFERENCES categories(id)
) ENGINE=InnoDB;

CREATE TABLE users (
    id         INT AUTO_INCREMENT PRIMARY KEY,
    name       VARCHAR(50) NOT NULL,
    email      VARCHAR(100) NOT NULL UNIQUE,
    phone      VARCHAR(20),
    address    VARCHAR(300),
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;

CREATE TABLE products (
    id          INT AUTO_INCREMENT PRIMARY KEY,
    category_id INT NOT NULL,
    name        VARCHAR(200) NOT NULL,
    price       DECIMAL(10,2) NOT NULL CHECK (price >= 0),
    stock       INT DEFAULT 0,
    FOREIGN KEY (category_id) REFERENCES categories(id)
) ENGINE=InnoDB;

CREATE TABLE orders (
    id           INT AUTO_INCREMENT PRIMARY KEY,
    user_id      INT NOT NULL,
    order_date   DATETIME DEFAULT CURRENT_TIMESTAMP,
    status       ENUM('pending','paid','shipped','delivered','cancelled')
                 DEFAULT 'pending',
    total_amount DECIMAL(12,2),
    FOREIGN KEY (user_id) REFERENCES users(id)
) ENGINE=InnoDB;

CREATE TABLE order_items (
    id         INT AUTO_INCREMENT PRIMARY KEY,
    order_id   INT NOT NULL,
    product_id INT NOT NULL,
    quantity   INT NOT NULL CHECK (quantity > 0),
    unit_price DECIMAL(10,2) NOT NULL,
    FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE,
    FOREIGN KEY (product_id) REFERENCES products(id)
) ENGINE=InnoDB;

변환 과정 검증 체크리스트

ER → 릴레이션 변환 검증 10항목
□  1. 모든 강한 개체가 테이블로 변환되었는가?
□  2. 약한 개체의 PK에 소유 개체의 PK가 포함되었는가?
□  3. 1:1 관계의 FK에 UNIQUE 제약이 있는가?
□  4. 1:N 관계의 FK가 N쪽 테이블에 배치되었는가?
□  5. M:N 관계가 교차 테이블로 해소되었는가?
□  6. 관계 속성이 적절한 테이블에 배치되었는가?
□  7. 다중값 속성이 별도 테이블로 분리되었는가?
□  8. 복합 속성이 하위 속성으로 분해되었는가?
□  9. 모든 FK의 참조 대상 테이블과 PK가 존재하는가?
□ 10. ON DELETE 정책이 업무 규칙에 맞게 설정되었는가?
ON DELETE 정책 가이드
┌──────────────┬──────────────────────────────────┐
│     정책     │ 사용 시점                        │
├──────────────┼──────────────────────────────────┤
│ CASCADE      │ 부모 삭제 시 자식도 삭제         │
│              │ 예: 주문 삭제 → 주문상세 삭제    │
├──────────────┼──────────────────────────────────┤
│ SET NULL     │ 부모 삭제 시 FK를 NULL로         │
│              │ 예: 부서 삭제 → 사원.dept_id=NULL│
├──────────────┼──────────────────────────────────┤
│ RESTRICT     │ 자식이 있으면 부모 삭제 불가     │
│ (NO ACTION)  │ 예: 회원 삭제 시 주문이 있으면 X │
├──────────────┼──────────────────────────────────┤
│ SET DEFAULT  │ 부모 삭제 시 FK를 기본값으로     │
│              │ 예: 카테고리 삭제 → '미분류'로   │
└──────────────┴──────────────────────────────────┘

변환 규칙 종합 정리

ER → 릴레이션 변환 핵심 요약
┌──────────────────────────────────────────────────────────┐
│            변환 규칙 종합 정리                           │
├──────────────────────────────────────────────────────────┤
│                                                          │
│  1. 강한 개체 → 테이블 (PK = 키 속성)                    │
│  2. 약한 개체 → 테이블 (PK = 소유PK + 부분키)            │
│  3. 1:1 → 전체 참여 쪽에 FK + UNIQUE                     │
│  4. 1:N → N쪽에 FK                                       │
│  5. M:N → 교차 테이블 (양쪽 PK를 FK로)                   │
│  6. 다중값 속성 → 별도 테이블                            │
│  7. 복합 속성 → 하위 속성을 개별 컬럼으로                │
│  8. 파생 속성 → 저장 여부 판단 (성능 vs 무결성)          │
│  9. 상속 → 단일/타입별/구체 테이블 전략 선택             │
│                                                          │
│  변환 순서:                                              │
│  강한 개체 → 약한 개체 → 1:1 → 1:N → M:N                 │
│  → 다중값 → 복합/파생 → 제약조건 → 인덱스                │
│                                                          │
└──────────────────────────────────────────────────────────┘

ER 모델을 릴레이션으로 변환하는 과정에서 데이터 무결성을 보장하기 위해 적절한 제약 조건(PK, FK, UNIQUE, CHECK, NOT NULL)을 함께 부여하는 것이 핵심입니다.

다음 장에서는 이렇게 만든 테이블이 올바른 구조인지 검증하는 정규화를 다루겠습니다.

목차