🔥 1. 정규화가 필요한 이유

📌 비정규화된 테이블 문제점

ID     | name     | class  | race  | level | inventory
--------------------------------------------------------
1001   | rookiss  | 마법사 | 휴먼  | 32    | 지팡이, 양초 * 2, 초록 물약 * 10
1005   | faker    | 전사   | 엘프  | 14    | 단검, 방패, 양초 * 4

🚨 문제점

  • inventory가 문자열로 저장됨 → 아이템 개별 조작 불가능
  • 같은 ID, name, class, race, level이 여러 행에 반복됨 → 중복 데이터 발생
  • 한 행의 크기가 너무 커짐 → 데이터 검색 및 수정 시 성능 저하

🔥 2. 1차 정규화 (First Normal Form, 1NF)

📌 "각 칸에는 하나의 값만 저장"

변경된 테이블

ID     | name     | class  | race  | level | itemCode | itemName  | itemCount
-----------------------------------------------------------------------------
1001   | rookiss  | 마법사 | 휴먼  | 32    | 13       | 지팡이    | 1
1001   | rookiss  | 마법사 | 휴먼  | 32    | 14       | 양초      | 2
1001   | rookiss  | 마법사 | 휴먼  | 32    | 15       | 초록 물약 | 10
1005   | faker    | 전사   | 엘프  | 14    | 21       | 단검      | 1
1005   | faker    | 전사   | 엘프  | 14    | 25       | 방패      | 1
1005   | faker    | 전사   | 엘프  | 14    | 14       | 양초      | 4

개선점

  • inventory가 개별 행으로 분리됨 → 개별 수정/삭제 가능
  • 중복 데이터 문제는 여전히 존재 (같은 name/class/race/level이 반복됨)

🔥 3. 2차 정규화 (Second Normal Form, 2NF)

📌 "중복 데이터 제거 + 부분적 종속성 제거"
📌 "기본 키(Primary Key)가 유일해야 한다"

테이블 분리

📌 players (플레이어 정보 저장)

ID     | name     | class  | race  | level
-----------------------------------------
1001   | rookiss  | 마법사 | 휴먼  | 32
1005   | faker    | 전사   | 엘프  | 14

📌 inventory (플레이어의 아이템 저장)

playerID | itemCode | itemCount
-------------------------------
1001     | 13       | 1
1001     | 14       | 2
1001     | 15       | 10
1005     | 21       | 1
1005     | 25       | 1
1005     | 14       | 4

개선점

  • 플레이어 정보와 인벤토리 정보 분리playerID로 관계 연결
  • 각 행은 중복 없이 최소 정보만 저장
  • 테이블이 더 작아지고 데이터 관리가 쉬워짐

🔥 4. 3차 정규화 (Third Normal Form, 3NF)

📌 "아이템 코드와 아이템 이름 분리"
📌 "의미상 분리 가능한 데이터는 별도 테이블로 분리"

테이블 추가

📌 itemInfo (아이템 정보 저장)

itemCode | itemName
-------------------
13       | 지팡이
14       | 양초
15       | 초록 물약
21       | 단검
25       | 방패

최종 정리

📌 players (플레이어 정보)

ID     | name     | class  | race  | level
-----------------------------------------
1001   | rookiss  | 마법사 | 휴먼  | 32
1005   | faker    | 전사   | 엘프  | 14

📌 inventory (플레이어의 아이템 저장)

playerID | itemCode | itemCount
-------------------------------
1001     | 13       | 1
1001     | 14       | 2
1001     | 15       | 10
1005     | 21       | 1
1005     | 25       | 1
1005     | 14       | 4

📌 itemInfo (아이템 코드별 정보)

itemCode | itemName
-------------------
13       | 지팡이
14       | 양초
15       | 초록 물약
21       | 단검
25       | 방패

개선점

  • 데이터 중복 완벽 제거
  • inventory 테이블에서 itemCode만 저장하면 itemInfo를 참조하여 아이템 이름을 불러올 수 있음
  • 데이터 수정이 간편해짐 (예: "양초"의 이름을 변경해도 itemInfo 테이블만 수정하면 됨)

🔥 5. 최종 SQL 테이블 설계

-- [플레이어 정보 테이블]
CREATE TABLE players (
    ID INTEGER PRIMARY KEY,
    name VARCHAR(20) NOT NULL,
    class VARCHAR(10) NOT NULL,
    race VARCHAR(10) NOT NULL,
    level INTEGER NOT NULL
);

-- [아이템 정보 테이블]
CREATE TABLE itemInfo (
    itemCode INTEGER PRIMARY KEY,
    itemName VARCHAR(20) NOT NULL
);

-- [인벤토리 테이블]
CREATE TABLE inventory (
    playerID INTEGER,
    itemCode INTEGER,
    itemCount INTEGER NOT NULL,
    PRIMARY KEY (playerID, itemCode),
    FOREIGN KEY (playerID) REFERENCES players(ID),
    FOREIGN KEY (itemCode) REFERENCES itemInfo(itemCode)
);

🔥 6. JOIN을 활용한 최종 데이터 조회

SELECT p.ID, p.name, p.class, p.race, p.level, i.itemName, inv.itemCount
FROM inventory inv
JOIN players p ON inv.playerID = p.ID
JOIN itemInfo i ON inv.itemCode = i.itemCode
ORDER BY p.ID;

결과 예시

ID     | name     | class  | race  | level | itemName  | itemCount
-----------------------------------------------------------------
1001   | rookiss  | 마법사 | 휴먼  | 32    | 지팡이    | 1
1001   | rookiss  | 마법사 | 휴먼  | 32    | 양초      | 2
1001   | rookiss  | 마법사 | 휴먼  | 32    | 초록 물약 | 10
1005   | faker    | 전사   | 엘프  | 14    | 단검      | 1
1005   | faker    | 전사   | 엘프  | 14    | 방패      | 1
1005   | faker    | 전사   | 엘프  | 14    | 양초      | 4

profile
李家네_공부방

0개의 댓글