사람들이 SQL 배울 때 JOIN 문법을 매우 어려워합니다.
그거 배우다보면 의문도 많이 생기고 왜 테이블을 애초에 여러개로 나눠놓는지 이해도 안가고 약간 반발심이 생길텐데
오늘 설명할 정규화/정규형이라는걸 배우게 되면 매우 쉬워집니다.
배워두면 나중에 DB 설계도 도움없이 알아서 잘할 수 있음
제1정규형 (1st normal form)
여러분은 지금부터 구민 체육센터 전산시스템 만드는 개발자입니다.
일단 체육센터에 수강 등록한 사람들을 테이블로 정리하고 싶은겁니다.
[수강등록현황 table]
회원번호 | 회원이름 | 프로그램 |
101 | 강호동 | 스쿼시초급 |
102 | 손흥민 | 헬스 |
103 | 김민수 | 헬스 |
그래서 테이블 하나 만들어서 이쁘게 잘 저장을 해놨습니다.
근데 '김민수' 라는 사람이 다음 날 '골프초급'을 또 수강신청한겁니다.
그럼 어떻게 데이터를 추가하죠?
[수강등록현황 table]
회원번호 | 회원이름 | 프로그램 |
101 | 강호동 | 스쿼시초급 |
102 | 손흥민 | 헬스 |
103 | 김민수 | 헬스, 골프초급 |
▲ 하나의 셀에 데이터를 더 추가하면 어떨까요.
그래도 되긴 합니다.
근데 보통은 이렇게 해놓으면 나중에 성능이슈가 생길 수 있습니다.
저렇게 한 칸에 많은 정보를 저장해두면 그 한 칸에서 일부만 찾기 / 일부만 수정 / 일부만 삭제 작업이 느려집니다.
엑셀에서도 저렇게 해놓으면 사수에게 빠따맞음
실은 JSON 데이터타입 아니면 array 데이터타입 (Postgres에서 가능) 사용하면
['헬스', '골프초급']
이런 식으로 여러개의 문자나 숫자를 한 칸에 저장할 수 있는데
그거 써도 마찬가지로 문제될 수 있습니다.
왜냐면 그냥 array, JSON은 문자와 취급이 비슷해서 나중에 array 자료 안의 일부 항목만 수정하는게 매우 어렵기 때문입니다.
(그래서 수정할 때는 새 값으로 아예 갈아치우거나 그런 식으로 많이 합니다)
[수강등록현황 table]
회원번호 | 회원이름 | 프로그램 |
101 | 강호동 | 스쿼시초급 |
102 | 손흥민 | 헬스 |
103 | 김민수 | 헬스 |
103 | 김민수 | 골프초급 |
▲ 그래서 이렇게 만드는게 낫습니다.
하나의 셀 안에는 하나의 데이터만 보관하는 겁니다.
이 작업이 완료된 테이블을 제1정규형 (1st normal form) 이라고 합니다.
이렇게 해두면 성능문제도 없어지고 나중에 다른 컬럼을 추가할 때도 문제가 안생길 수 있습니다.
(참고)
예전에 배운 비관계형 데이터베이스들은 제1 정규화를 안하는 경우가 있습니다.
하지만 관계형 데이터베이스는 제1 정규화 안해놓으면 단점이 많아서 데이터 저장할 때 항상 하도록 합시다.
제2정규형 (2nd normal form)
[수강등록현황 table]
회원번호 | 회원이름 | 프로그램 | 가격 | 납부여부 |
101 | 강호동 | 스쿼시초급 | 5000 | 0 |
102 | 손흥민 | 헬스 | 6000 | 1 |
103 | 김민수 | 헬스 | 6000 | 1 |
103 | 김민수 | 골프초급 | 8000 | 0 |
아까 제1정규화 해놓은 테이블이 있습니다.
심심해서 각 프로그램마다 '가격'이랑 '납부여부'를 기록하는 컬럼도 만들어놨습니다.
잘 돌아갈 것 같은데 근데 이런 문제가 생길 수도 있습니다.
Q. '헬스' 프로그램의 가격에 오류가 있어서 6000에서 7000으로 변경되어야하면 어쩌죠?
- 2개 각각 수정하면 됩니다.
Q. 근데 장사가 잘되어서 '헬스'를 신청한 사람이 100명이면 어쩌죠?
100개 행을 전부 6000 -> 7000 이렇게 바꿔야지 꼼수 그런거 없습니다.
100개 행을 고치는 불상사가 생기는게 싫다면
현재 테이블의 주제와 관련없는 컬럼은 다른 테이블로 옮기십시오.
[수강등록현황 table]
회원번호 | 회원이름 | 프로그램 | 가격 | 납부여부 |
101 | 강호동 | 스쿼시초급 | 5000 | 0 |
102 | 손흥민 | 헬스 | 6000 | 1 |
103 | 김민수 | 헬스 | 6000 | 1 |
103 | 김민수 | 골프초급 | 8000 | 0 |
[프로그램 table]
프로그램 | 가격 |
스쿼시초급 | 5000 |
헬스 | 6000 |
골프초급 | 8000 |
'가격' 컬럼은 수강등록현황과 별로 상관이 없고 '프로그램' 종류에 따라서 결정될 뿐입니다.
그래서 '가격' 컬럼은 현재 테이블의 주제와 맞지 않기 때문에
그걸 잘라내서 새로운 테이블 만들어서 거기 넣어봤습니다.
이 작업이 완료된 테이블을 제2정규형 (2nd normal form) 이라고 합니다.
장점은 아까처럼 '헬스'의 가격이 수정되어야할 때 100곳을 수정할 필요가 없어짐
물론 이러면 단점도 있는데 나중에 김민수라는 사람이 얼마를 내야할지 조회하는게 귀찮아질 수 있는데
그건 나중에 SQL JOIN 문법 쓰면 됩니다.
제2정규형 - 어려운버전
제2정규형의 교과서적 정의는 partial dependency를 제거한 테이블입니다.
쉽게 설명해보자면
1. composite primary key 라는게 있습니다.
primary key는 행을 서로 구분할 수 있는 유니크한 데이터를 담고있는 컬럼입니다.
근데 가끔은 하나의 컬럼만으로 primary key를 정할 수 없는 경우가 있습니다.
[수강등록현황 table]
회원번호 | 회원이름 | 프로그램 | 가격 | 납부여부 |
101 | 강호동 | 스쿼시초급 | 5000 | 0 |
102 | 손흥민 | 헬스 | 6000 | 1 |
103 | 김민수 | 헬스 | 6000 | 1 |
103 | 김민수 | 골프초급 | 8000 | 0 |
▲ 위의 테이블에선 (회원번호 + 프로그램) 이렇게 조합해야 primary key 역할을 수행할 수 있습니다.
'회원번호' 만으로 primary key 역할은 불가능합니다.
'프로그램' 만으로 primary key 역할은 불가능합니다.
근데 두개 합치면 primary key 역할 가능
두개 컬럼을 합친 primary key를 composite primary key 라고 합니다.
2. composite primary key 중에 하나의 컬럼에만 종속되어 있는 따까리 컬럼을
partial dependency가 있다고 표현합니다.
[수강등록현황 table]
회원번호 | 회원이름 | 프로그램 | 가격 | 납부여부 |
101 | 강호동 | 스쿼시초급 | 5000 | 0 |
102 | 손흥민 | 헬스 | 6000 | 1 |
103 | 김민수 | 헬스 | 6000 | 1 |
103 | 김민수 | 골프초급 | 8000 | 0 |
▲ 예를 들어 위의 테이블에서 보면 '가격' 컬럼은 '프로그램'에 따라서 결정될 뿐 '회원번호'과는 상관이 없습니다.
(진짜 그런지 잘 생각해보십쇼)
그 경우 '가격' 컬럼은 partial dependency가 있다고 표현합니다.
3. partial dependency가 있는 컬럼을 다른 테이블로 빼면 제2정규형 테이블 완성입니다.
그래서 위의 예시의 '가격' 컬럼을 다른 테이블로 빼는 것입니다.
아이쉽다
쉬우니까 연습한번 해봅시다.
[수강등록현황 table]
회원번호 | 회원이름 | 프로그램 | 가격 | 준비물 |
101 | 강호동 | 스쿼시초급 | 5000 | 라켓 |
102 | 손흥민 | 헬스 | 6000 | 없음 |
103 | 김민수 | 헬스 | 6000 | 없음 |
103 | 김민수 | 골프초급 | 8000 | 골프채 |
Q1. 위 테이블에서 '준비물' 컬럼은 partial dependency가 있을까요 없을까요?
있습니다.
composite primary key 중 하나인 회원번호에 종속 X
composite primary key 중 하나인 프로그램에 종속 O
그래서 제2정규형 만들려면 다른 테이블로 빼야합니다.
[수강등록현황 table]
회원번호 | 회원이름 | 프로그램 | 가격 | 돈납부여부 |
101 | 강호동 | 스쿼시초급 | 5000 | 0 |
102 | 손흥민 | 헬스 | 6000 | 1 |
103 | 김민수 | 헬스 | 6000 | 1 |
103 | 김민수 | 골프초급 | 8000 | 0 |
Q2. 위 테이블에서 '돈납부여부' 컬럼은 partial dependency가 있을까요 없을까요?
없습니다.
composite primary key 중 하나인 회원번호에 종속 X
composite primary key 중 하나인 프로그램에 종속 X
하지만 (회원번호 + 프로그램)에 종속 O 입니다.
그래서 제2정규형 만들려고 다른 테이블로 뺄 필요는 없을듯요
(팁) 종속관계 판단이 어렵다면 하나의 컬럼을 다른 값으로 바꿔보십시오.
그 경우 다른 컬럼도 변경되어야한다면 그 관계를 종속관계라고 합니다.
나는 빡통이라 교과서적 정의 싫고 단순하게 생각하고 싶다면
그냥 현재 테이블 주제와 관련없는 데이터들은 다 다른 테이블로 빼면
제2정규형 만들기 끝입니다.
오늘의 숙제 :
[책대여내역 table]
회원아이디 | 책이름 | 날짜 | 회원등급 | 책가격 | 반납여부 |
lee | 디자인책 | 1월1일 | 우수 | 1000 | 1 |
kim | 만화책 | 1월2일 | 일반 | 2000 | 0 |
park | SQL책 | 1월3일 | 일반 | 1000 | 1 |
park | 소설책 | 1월3일 | 일반 | 2000 | 0 |
Q1. 위 테이블에서 책가격 컬럼은 다른 테이블로 옮기는게 좋을까요?
위 테이블에서 composite primary key는 (회원아이디 + 책이름 + 날짜) 같군요.
근데 이 중에서 '책이름 컬럼'에만 종속되어있으니
제2정규형 테이블 만들고 싶으면 옮기는게 좋겠군요.
Q2. 위 테이블에서 회원등급 컬럼은 다른 테이블로 옮기는게 좋을까요?
위 테이블에서 composite primary key는 (회원아이디 + 책이름 + 날짜) 같군요.
근데 이 중에서 '회원아이디 컬럼'에만 종속되어있으니
제2정규형 테이블 만들고 싶으면 옮기는게 좋겠군요.
Q3. 위 테이블에서 반납여부 컬럼은 다른 테이블로 옮기는게 좋을까요?
composite primary key는 (회원아이디 + 책이름 + 날짜) 3개 중에
하나의 컬럼에만 달랑 종속되진 않습니다.
(회원아이디 + 책이름 + 날짜) 조합마다 종속되어야하기 때문에 옮길 필요는 없습니다.
그냥 빡통식으로 쉽게 생각하면 '반납여부'는 [책대여내역 table] 이라는 주제와 관련 있습니까?
매우 관련있어보이기 때문에 옮기면 안됩니다.
'Mysql&DBeaver' 카테고리의 다른 글
DBeaver)테이블 2개 합쳐서 출력은 INNER JOIN (1) | 2024.09.06 |
---|---|
DBeaver)제3정규형 (3NF) & Foreign Key (0) | 2024.09.06 |
DBeaver)컬럼에 안전하게 제약 (Constraints) 주기 (0) | 2024.09.06 |
DBeaver)중요한 IF / CASE 문법 (0) | 2024.09.06 |
DBeaver)그룹지어 통계낼 땐 GROUP BY (1) | 2024.09.06 |