컬럼은 이름만 붙인 칸이 아니라
데이터의 약속이다
지난 강의에서 컬럼은 모든 행에 던지는 같은 질문이라고 했습니다. 그렇다면 컬럼 이름만 적어두면 끝일까요? 여기에 이름을 적어도 되는지, 값을 모르면 비워도 되는지, 아무것도 적지 않았을 때 자동으로 들어갈 값은 있는지 — 이것까지 정해야 컬럼이 완성됩니다.
이번 섹션의 여정
완료 ✓
지금 여기
값에 맞는 그릇
기본키 · 외래키 · 테이블 만들기
오늘은 약속을 네 가지로 나눠봅니다
컬럼은 단순한 빈칸이 아닙니다. 어떤 값을 어떤 규칙으로 기록할지 정한 약속이에요. 하나씩 보겠습니다.
컬럼 이름은 표지판입니다
먼저 우리 실습용 members 테이블의 컬럼을 보겠습니다.
| 컬럼 | 타입 | 규칙 | 담는 것 |
|---|---|---|---|
| member_id | INT | NOT NULL | 회원 번호 |
| member_name | VARCHAR(50) | NOT NULL | 회원 이름 |
| gender | CHAR(1) | NOT NULL | 성별 (M/F) |
| age | INT | NOT NULL | 나이 |
| joined_at | DATE | NOT NULL | 가입일 |
컬럼 이름은 길을 알려주는 표지판과 같습니다. 만약 모든 컬럼 이름이 data1, data2, data3이라면 어떨까요? 값은 들어 있어도 그 값이 무엇을 뜻하는지 매번 설명서를 찾아야 합니다.
date처럼 너무 넓은 이름도 상황에 따라 헷갈립니다. 가입한 날짜인지, 주문한 날짜인지 알기 어렵기 때문이에요. 그래서 우리 스키마는 이렇게 구분했습니다.
| 이렇게 두면 | 이렇게 나누면 |
|---|---|
| date — 무슨 날짜인지 모름 | joined_at — 가입일 |
| date — 무슨 날짜인지 모름 | ordered_at — 주문일 |
이건 사람에게만 좋은 게 아니에요. AI에게 스키마를 보여주고 SQL을 요청할 때도 — 이름이 분명할수록 AI가 컬럼의 뜻을 잘못 추측할 가능성이 줄어듭니다.
한 컬럼에는 한 가지 의미만
이번에는 일부러 잘못 만들어 보겠습니다. 한 컬럼 안에 나이와 성별을 함께 적는 겁니다.
| member_name | age_gender |
|---|---|
| 김철수 | 35/M |
| 이영희 | 28/F |
사람 눈에는 뜻이 보이지만, 데이터베이스가 나이만 필요할 때는 매번 값을 둘로 잘라야 합니다. 나이가 30 이상인 회원을 찾거나, 나이만 수정하기도 불편해지고요. 그래서 실제 members 테이블은 age와 gender를 따로 두었습니다.
상품도 마찬가지입니다. products 테이블에서 상품명과 가격을 무선 이어폰 / 89000처럼 한 칸에 넣지 않고 — product_name과 price로 나눕니다. 이렇게 해야 이름은 이름대로 찾고, 가격은 가격대로 계산하거나 비교할 수 있어요.
NULL — 아직 값이 없다는 표시
회원이 가입할 때 아직 별명을 정하지 않았다고 해보겠습니다. 별명을 담는 nickname 컬럼이 있다면 그 칸에는 무엇을 넣어야 할까요?
이때 사용할 수 있는 특별한 표시가 NULL입니다.
| 이 값은 | 뜻 |
|---|---|
| 0 | 숫자 영(零) — 기록된 값이 있음 |
| '' | 빈 문자열 — 기록된 값이 있음 |
| '없음' | 없음이라는 글자 — 기록된 값이 있음 |
| NULL | 현재 기록된 값이 없음 |
아직 몰라서 기록하지 못한 경우도 있고, 그 사람에게는 해당되지 않는 정보일 수도 있습니다. 별명이 없는 것과 별명이 정말로 없음인 사람은 다릅니다. 전화번호를 모르는 것과 전화번호가 숫자 0인 것도 완전히 다르죠.
그래서 값이 없다는 상태를 다른 값으로 억지로 대신하지 않고 NULL로 구분합니다. 다만 모든 컬럼에 NULL을 허용하는 게 좋은 건 아니에요 — 꼭 필요한 값까지 빠질 수 있으니까요.
지금 사용하는 shop 스키마에는 nickname 컬럼이 없습니다. 이 예시는
NULL의 뜻을 설명하기 위한 가상의 컬럼이에요.
NOT NULL — 반드시 답하라는 약속
값이 반드시 있어야 하는 컬럼에는 NOT NULL 규칙을 붙입니다. 말 그대로 NULL을 허용하지 않겠다는 뜻이에요.
실제 members 테이블의 member_name, gender, age, joined_at은 **모두 NOT NULL**입니다. 회원 이름이나 가입일이 빠진 불완전한 행이 들어오지 못하게 막아둔 거예요. products 테이블의 product_name과 price, orders 테이블의 ordered_at도 모두 NOT NULL입니다.
선택 항목비워둔 채로 저장할 수 있다
신청서로 치면안 써도 제출되는 칸
필수 항목비우면 저장 자체가 거부된다
신청서로 치면써야만 제출되는 칸
필수 항목을 비운 채 저장하려고 하면 — 데이터베이스가 약속 위반이라고 알려줍니다.
NOT NULL은 값이 빠지지 않았는지를 확인하는 규칙입니다. 나이에 말이 안
되는 숫자가 들어갔는지까지 판단해주는 규칙은 아닙니다.
DEFAULT — 생략했을 때 저장되는 기본값
마지막은 DEFAULT, 기본값입니다.
테이블에 새로운 데이터가 생성된다는 건 새로운 행이 하나 추가된다는 뜻이죠. 새 행이 추가될 때는 각 컬럼에 들어갈 값을 함께 저장합니다. 이때 어떤 컬럼에 DEFAULT가 설정되어 있고 그 컬럼의 값을 명시적으로 넣지 않았다면 — 데이터베이스는 미리 정해둔 기본값을 저장합니다.
가상의 상품 테이블에서 status 컬럼의 기본값을 판매중으로 정했다고 해볼게요.
| 새 행을 저장할 때 | status 에 실제로 저장되는 값 |
|---|---|
| 이름과 가격만 넣고 status 는 생략 | 판매중 ← 기본값 |
| status 에 '품절' 을 명시 | 품절 ← 입력한 값 |
새 행이 추가될 때 해당 컬럼의 값을 생략하면 기본값이 저장되고, 값을 명시하면 명시한 값이 저장됩니다.
DEFAULT는 데이터베이스가 상황을 보고 추측하는 값이 아니라, 테이블을 설계할 때 미리 정해놓은 값이라는 점을 기억하세요.
세 규칙을 함께 읽는 법
이제 컬럼 하나를 볼 때 이름만 읽지 말고 세 가지를 함께 확인해 보세요.
실제 상품 테이블의 price INT NOT NULL을 이 방식으로 읽어보겠습니다.
| 질문 | 이 컬럼의 답 |
|---|---|
| ① 무엇을 뜻하는가 | 원 단위 상품 가격 |
| ② 값이 없어도 되는가 | 아니오 — 가격이 빠진 상품은 저장 불가 |
| ③ 기본값이 있는가 | 없음 — 넣을 때 가격을 직접 알려줘야 함 |
한눈에 정리
| 개념 | 한 줄 정의 | 예시 |
|---|---|---|
| 컬럼 이름 | 값의 뜻을 알려주는 표지판 | date 보다 joined_at |
| 한 컬럼 = 한 의미 | 따로 찾고·비교하고·바꿀 값은 따로 담는다 | 35/M 대신 age + gender |
| NULL | 현재 기록된 값이 없다는 특별한 상태 | 0, '', '없음' 과 모두 다름 |
| NOT NULL | 반드시 값이 있어야 한다는 규칙 | members.member_name |
| DEFAULT | 값을 생략했을 때 저장되는 미리 정한 기본값 | status → 판매중 |
결국 컬럼은 이름만 붙인 칸이 아닙니다 — 무엇을 담고, 비워도 되는지까지 정한 데이터의 약속입니다.
그런데 값이 있기만 하면 약속을 지킨 걸까요? 가격을 글자로 저장하거나, 전화번호를 숫자로 저장하면 어떤 문제가 생길까요? 그 이야기가 다음 강의입니다.