자격증/SQLD

SQL 정규화 완전정복

2주녘 2025. 5. 17. 13:58
반응형

💾 비정규형 테이블 (Non-Normalized Table)

-- 비정규형 주문 테이블 (ProductList에 다중값 저장)
CREATE TABLE orders_raw (
    order_id    VARCHAR(10),
    customer    VARCHAR(100),
    product_list VARCHAR(255),   -- 쉼표로 묶은 다중 값
    total_price INT
);

INSERT INTO orders_raw VALUES ('001', 'Alice', 'TV,Phone', 1500);
INSERT INTO orders_raw VALUES ('002', 'Bob', 'Laptop', 1000);

❌ 문제점

  • product_list 컬럼에 쉼표로 구분된 다중 값이 들어 있음
  • 제품 하나하나에 대한 정보가 분리되어 있지 않아서 분석이나 검색이 어려움
  • 수정, 삭제, 추가 시 데이터 이상(Anomaly)이 발생할 가능성 큼

 

🥇 1정규형 (1NF) - 원자값으로 분리

테이블의 모든 컬럼은 더 이상 쪼갤 수 없는 단일 값(Atomic Value)만 포함해야 합니다.
-- 1NF: 하나의 제품 단위로 분해
CREATE TABLE orders_1nf (
    order_id    VARCHAR(10),
    customer    VARCHAR(100),
    product     VARCHAR(100),
    total_price INT
);

INSERT INTO orders_1nf VALUES ('001', 'Alice', 'TV', 1500);
INSERT INTO orders_1nf VALUES ('001', 'Alice', 'Phone', 1500);
INSERT INTO orders_1nf VALUES ('002', 'Bob', 'Laptop', 1000);

 

🧠 설명

  • 제품을 개별 행으로 분리
  • 이렇게 하면 특정 제품에 대한 주문을 쉽게 조회하거나 통계 내기도 쉬워져요.

 

🥈 2정규형 (2NF) - 부분 종속 제거

복합키가 있는 테이블에서, 기본키 일부에만 의존하는 컬럼을 분리합니다.
-- 주문 테이블 (기본 정보만)
CREATE TABLE orders (
    order_id    VARCHAR(10) PRIMARY KEY,
    customer    VARCHAR(100),
    total_price INT
);

-- 주문 상세 테이블 (제품 단위)
CREATE TABLE order_products (
    order_id    VARCHAR(10),
    product     VARCHAR(100),
    PRIMARY KEY (order_id, product),
    FOREIGN KEY (order_id) REFERENCES orders(order_id)
);

-- 데이터 삽입
INSERT INTO orders VALUES ('001', 'Alice', 1500);
INSERT INTO orders VALUES ('002', 'Bob', 1000);

INSERT INTO order_products VALUES ('001', 'TV');
INSERT INTO order_products VALUES ('001', 'Phone');
INSERT INTO order_products VALUES ('002', 'Laptop');

 

❗ 문제

  • total_price는 실제로 order_id에만 종속되는 값이에요.
  • 그런데 현재는 order_id + product라는 복합키에 total_price가 연결되어 있어서 중복 저장되고 있어요.

🧠 설명

  • total_price는 주문 전체에 대한 정보니까 주문 기본 테이블에!
  • 제품은 제품대로 order_products에 저장하면 중복 제거 성공!

 

✅ 3정규형 (3NF) - 이행 종속 제거

기본키가 아닌 컬럼이 다른 일반 컬럼에 종속되면, 별도로 분리해야 합니다.
-- 예시: 지역정보가 고객명에 따라 결정됨 (이행 종속)
-- orders 테이블에 다음처럼 저장된다고 가정
+----------+-----------+-------------+---------+
| OrderID  | Customer  | TotalPrice  | Region  |
+----------+-----------+-------------+---------+
| 001      | Alice     | 1500        | Seoul   |
| 002      | Bob       | 1000        | Busan   |

 

  • Region은 사실상 Customer에 종속된 정보예요.
  • 고객의 지역이 자주 바뀌는 경우, 여러 행을 동시에 수정해야 해서 갱신 이상이 발생할 수 있어요.

 

-- 고객 테이블로 분리 (Region은 Customer에 종속되므로)
CREATE TABLE customers (
    customer    VARCHAR(100) PRIMARY KEY,
    region      VARCHAR(100)
);

-- orders 테이블은 customer만 참조하도록 유지
-- (이미 생성되어 있으면 ALTER로 FK 설정해도 OK)

-- 고객 데이터 삽입
INSERT INTO customers VALUES ('Alice', 'Seoul');
INSERT INTO customers VALUES ('Bob', 'Busan');

🧠 설명

  • 고객 정보를 별도 테이블로 분리하여 데이터 중복 제거 + 관리 효율성 향상!

 

 

🧪 실습 쿼리 예시

-- 주문자별 주문 총액 확인
SELECT o.customer, o.total_price
FROM orders o;

-- 주문별 주문한 제품 확인
SELECT op.order_id, op.product
FROM order_products op;

-- 고객 지역 포함 전체 조회
SELECT o.order_id, o.customer, c.region, o.total_price
FROM orders o
JOIN customers c ON o.customer = c.customer;

 

 

🎯 요약

정규형 핵심 변경 내용 대표 테이블 구조
1NF 다중값 분리 (쉼표 → 행 분리) orders_1nf
2NF 주문정보 / 제품정보 분리 orders, order_products
3NF 고객의 지역정보 분리 customers (Customer → Region 종속)
반응형