[아이티센 부트캠프] 14일차 (MySQL 4)

이언덕·2026년 4월 2일

아이티센 부트캠프

목록 보기
35/115
post-thumbnail

1. 데이터 조작하기 (DML)

개념

앞에서는 데이터를 조회하고, 정렬하고, 묶어서 보는 방법을 배웠다.
이제는 한 단계 더 나아가서 테이블 안의 데이터를 직접 바꾸는 작업을 봐야 한다.

이 파트에서는 조회가 아니라, 이미 만들어진 테이블 안의 행 데이터를 실제로 바꾸는 문장에 집중한다.
즉, 새 데이터를 넣거나, 기존 데이터를 수정하거나, 필요 없는 데이터를 삭제하는 작업이 여기에 들어간다. INSERT, UPDATE, DELETE는 테이블의 행 데이터를 조작하는 대표적인 문장이고, 이런 변경 작업은 트랜잭션과 연결되어 논리적인 작업 단위로 다뤄진다.

여기서 가장 먼저 잡아야 할 것은 아주 단순하다.

  • INSERT는 새 행을 추가하는 문장
  • UPDATE는 기존 행의 값을 바꾸는 문장
  • DELETE는 기존 행을 지우는 문장

즉, 이 파트의 핵심은
이미 들어 있는 데이터를 어떻게 안전하게 넣고, 바꾸고, 지울 것인가다.

예제에서는 EMP 테이블을 기준으로 본다.
EMP 테이블은 기존 직원 데이터를 수정하거나 삭제하는 흐름을 보기 좋고, 새 직원을 추가하는 INSERT 예제까지 함께 확인할 수 있기 때문이다.

INSERT로 데이터 추가하기

INSERT는 테이블에 새로운 행을 추가할 때 사용하는 문장이다.
쉽게 말하면 빈 테이블에 첫 데이터를 넣거나, 기존 테이블에 새 데이터를 한 줄 더 추가하는 작업이다. 열 이름은 생략할 수 있지만, 그 경우 VALUES 뒤에 오는 값의 순서와 개수가 테이블 정의 순서와 정확히 맞아야 한다.

가장 기본적인 형태는 아래와 같다.

insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (9900, 'JACKSON', 'SALESMAN', 7839, '1983-02-05', 900, 100, 10);

이 문장은 EMP 테이블에
직원번호가 9900이고, 이름이 JACKSON이며, 직무가 SALESMAN인 새 직원 행 하나를 추가한다.

처음 보면 단순해 보이지만, INSERT에서 자주 헷갈리는 부분이 있다.
바로 열 이름을 생략할 수 있다는 점이다.

예를 들어 지금처럼

insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (9900, 'JACKSON', 'SALESMAN', 7839, '1983-02-05', 900, 100, 10);

이렇게 쓰면 어떤 열에 어떤 값이 들어가는지 더 분명하게 보인다.
반대로 열 이름을 생략하면, 테이블에 정의된 열 순서를 정확히 알고 있어야 한다.
그래서 처음에는 열 이름을 함께 쓰는 방식이 훨씬 덜 헷갈린다.


INSERT에서 꼭 알아야 하는 것

1) 열 이름을 생략하면 값 순서를 정확히 맞춰야 한다

열 이름을 쓰지 않으면 편해 보일 수 있다.
하지만 그 대신 VALUES 안에 넣는 값 순서가 테이블의 열 순서와 정확히 같아야 한다.

예를 들어 EMP처럼 컬럼이 많은 테이블은
값 순서를 하나만 잘못 넣어도 의미가 완전히 달라지거나 오류가 날 수 있다.

즉, INSERT는
값만 넣는 문장처럼 보여도, 실제로는 어떤 열에 들어가는 값인지 정확히 맞춰야 하는 문장이다.


2) INSERT는 기존 데이터를 바꾸는 문장이 아니라 새 행을 추가하는 문장이다

INSERT는 기존 직원의 급여를 고치는 문장이 아니다.
원래 없던 직원을 새로 추가하는 문장이다.

예를 들어 JACKSON 예제는
기존 데이터를 수정하는 것이 아니라 EMP 테이블에 새 직원 한 명을 추가하는 흐름으로 이해하면 된다.

예제: 새로운 직원 데이터 추가하기

INSERT는 새 행을 추가하는 문장이기 때문에,
실행 전에는 먼저 정말 없는 데이터인지 조회로 확인하고, 실행 후에는 정상적으로 들어갔는지 다시 조회로 확인하는 흐름으로 보는 것이 좋다.

select *
from emp
where ename = 'JACKSON';

insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
values (9900, 'JACKSON', 'SALESMAN', 7839, '1983-02-05', 900, 100, 10);

select *
from emp
where ename = 'JACKSON';
실행 전실행 후

실행 전 조회에서는 JACKSON이라는 이름의 직원이 없으므로 결과가 나오지 않는다.
그다음 INSERT를 실행하면, EMP 테이블에 새 직원 한 명이 추가된다.
마지막 조회에서는 방금 넣은 JACKSON 행이 정상적으로 조회되는 것을 확인할 수 있다.

여기서 중요한 점은 KING의 이름을 직접 넣는 것이 아니라,
관리자 번호 컬럼인 mgr에 7839를 넣는다는 점이다.
즉, INSERT를 볼 때는 단순히 값을 넣는 것보다 어떤 컬럼에 어떤 의미의 값이 들어가는지를 같이 보는 습관이 중요하다.



UPDATE로 기존 데이터 수정하기

UPDATE는 이미 들어 있는 행의 값을 수정할 때 사용하는 문장이다.
즉, 새 행을 추가하는 것이 아니라, 이미 있는 행의 내용 일부를 바꾸는 작업이다. UPDATE는 기존 값을 바꾸는 문장이고, WHERE를 생략하면 테이블의 전체 행 내용이 바뀔 수 있어 주의가 필요하다.

가장 기본적인 형태는 아래와 같다.

update emp
set sal = 5000
where empno = 7499;

이 문장은 EMP 테이블에서
직원번호가 7499인 행을 찾아
그 행의 sal 값을 5000으로 바꾼다.

즉, UPDATE는 크게 두 부분으로 보면 된다.

  • SET
    → 무엇을 어떻게 바꿀지

  • WHERE
    → 어떤 행을 바꿀지

이 두 개가 같이 있어야
의도한 데이터만 정확하게 수정할 수 있다.

UPDATE에서 가장 중요한 것

UPDATE에서 가장 중요한 것은 사실 SET보다 WHERE다.

왜냐하면 WHERE가 없으면
“어떤 행만 바꿀지”가 사라지기 때문이다.

예를 들어 아래 문장을 보자.

update emp
set sal = 5000;

이 문장은 특정 직원 하나의 급여를 고치는 것이 아니다.
테이블에 있는 모든 행의 급여를 전부 5000으로 바꾸는 문장이 된다.

초보자가 가장 자주 하는 실수도 이 부분이다.
한 줄만 바꾼다고 생각하고 실행했는데, 실제로는 테이블 전체가 바뀌어 버리는 경우가 생긴다.

또 WHERE가 있다고 해서 항상 한 행만 바뀌는 것도 아니다.
조건에 맞는 행이 여러 개면 그 행들이 모두 함께 수정된다.

즉, UPDATE는
무엇을 바꾸는지보다, 어느 행을 바꾸는지가 더 중요하다고 이해하면 된다.

예제: 특정 직원 급여 수정하기

한 직원의 값을 바꾸는 문제도
바로 UPDATE부터 쓰기보다 수정 전 조회 → 수정 → 수정 후 조회 흐름으로 보면 더 이해가 쉽다.

select empno as '직원번호', sal as '급여'
from emp
where empno = 7499;

update emp
set sal = 5000
where empno = 7499;

select empno as '직원번호', sal as '급여'
from emp
where empno = 7499;
수정 전수정 후

처음 조회에서는 7499번 직원의 기존 급여가 보인다.
그다음 UPDATE를 실행하면 해당 직원의 급여가 5000으로 변경된다.
마지막 조회에서는 정말로 7499번 직원 한 명의 급여만 바뀌었는지 확인할 수 있다.

이 예제에서 핵심은
where empno = 7499가 들어 있어서
전체가 아니라 특정 조건에 맞는 행만 수정한다는 점이다.

즉, UPDATE를 볼 때는
먼저 SET보다 WHERE를 확인하는 습관이 중요하다.

예제: 여러 직원의 급여를 한 번에 수정하기

이번에는 한 사람만 바꾸는 것이 아니라,
조건에 맞는 여러 직원의 급여를 한 번에 바꾸는 흐름이다.

select deptno as '부서번호', sal as '급여'
from emp
where deptno = 20;

update emp
set sal = sal * 1.1
where deptno = 20;

select deptno as '부서번호', sal as '급여'
from emp
where deptno = 20;
수정 전수정 후

처음 조회에서는 20번 부서 직원들의 현재 급여가 보인다.
그다음 UPDATE를 실행하면 그 직원들의 급여가 각각 현재 급여 기준으로 10% 인상된다.
마지막 조회에서는 20번 부서 직원들의 급여가 실제로 올라간 것을 확인할 수 있다.

이 예제에서 봐야 할 핵심은 두 가지다.
첫째, 고정값으로 바꾸는 것이 아니라 기존 값을 기준으로 계산해서 수정한다는 점이다.
둘째, 조건에 맞는 직원이 여러 명이면 여러 행이 함께 수정된다는 점이다.



DELETE로 기존 데이터 삭제하기

DELETE는 테이블에 들어 있는 행을 삭제할 때 사용하는 문장이다.
즉, 테이블 구조를 없애는 것이 아니라, 행 데이터만 지우는 작업이다. DELETE FROM은 행 단위 삭제이고, WHERE를 생략하면 전체 데이터가 삭제된다.

가장 기본적인 형태는 아래와 같다.

delete from emp
where deptno = 20;

이 문장은 EMP 테이블에서
부서번호가 20인 행을 삭제한다.

즉, DELETE도 UPDATE와 마찬가지로
WHERE가 매우 중요하다.

DELETE에서도 WHERE가 중요하다

예를 들어 아래 문장을 보자.

delete from emp;

이 문장은 특정 직원 하나를 지우는 문장이 아니다.
EMP 테이블 안의 모든 행 데이터를 삭제한다.

즉, 테이블은 남아 있지만
그 안의 내용은 전부 비게 된다.

그래서 DELETE를 볼 때도
항상 먼저 WHERE가 있는지부터 확인해야 한다.

그리고 WHERE가 있다고 해서 항상 한 행만 삭제되는 것도 아니다.
조건에 맞는 행이 여러 개면 그 행들이 모두 함께 삭제된다.

초보자 입장에서는
UPDATE와 DELETE는 둘 다 WHERE를 빼면 매우 위험한 문장이라고 기억하면 된다.

예제: 특정 조건의 직원 데이터 삭제하기

삭제 문제도 마찬가지로
실행 전에 어떤 행이 대상인지 먼저 조회하고, 삭제 후에는 정말 사라졌는지 다시 조회하는 흐름으로 확인하는 것이 좋다.

select deptno as '부서번호', ename as '직원명'
from emp
where deptno = 20;

delete from emp
where deptno = 20;

select deptno as '부서번호', ename as '직원명'
from emp
where deptno = 20;
삭제 전삭제 후

처음 조회에서는 20번 부서에 속한 직원들이 보인다.
그다음 DELETE를 실행하면 20번 부서 직원들이 삭제된다.
마지막 조회에서는 20번 부서 직원이 더 이상 조회되지 않는 것을 확인할 수 있다.

이 예제의 핵심도 같다.
행 일부만 지우고 싶은데 WHERE가 빠지면 전체가 지워질 수 있다는 점이다.

예제: 급여 조건으로 여러 직원 삭제하기

이번에는 부서번호처럼 딱 정해진 값이 아니라,
급여 조건으로 삭제 대상을 찾는 흐름이다.

select sal as '급여', ename as '직원'
from emp
where sal <= 1000;

set sql_safe_updates = 0;

delete from emp
where sal <= 1000;

set sql_safe_updates = 1;

select sal as '급여', ename as '직원'
from emp
where sal <= 1000;
삭제 전삭제 후

처음 조회에서는 급여가 1000 이하인 직원들이 보인다.
그다음 DELETE를 실행하면 그 직원들이 삭제된다.
마지막 조회에서는 해당 조건을 만족하는 직원이 더 이상 보이지 않는 것을 확인할 수 있다.

이 예제에서 봐야 할 포인트는
이름이나 사번처럼 특정 값 하나를 지정하는 방식이 아니라, 비교 조건으로 삭제 대상을 찾는 방식이라는 점이다.
또 실습 환경에 따라서는 safe update 설정 때문에 삭제가 바로 안 될 수 있어서, 위처럼 잠깐 설정을 조정하는 흐름이 함께 들어갈 수 있다.


DELETE, TRUNCATE, DROP은 어떻게 다른가`

처음에는 셋 다 “지운다”는 느낌이라 섞이기 쉽다.
하지만 실제로는 지우는 대상이 다르다.

1) DELETE

DELETE는 행 데이터를 지운다.
테이블 구조는 그대로 남는다.

즉,

  • 테이블은 계속 존재하고
  • 그 안의 데이터만 지워진다


2) TRUNCATE

TRUNCATE는 테이블 구조는 남겨 두고, 안의 데이터 전체를 한 번에 비우는 문장이다.

즉,

  • 테이블은 그대로 남고
  • 들어 있던 행 데이터만 전체 삭제된다

그래서 TRUNCATE는 특정 행 몇 개를 지우는 문장이라기보다,
테이블 내용을 통째로 비우는 방식이라고 이해하면 된다.


3) DROP

DROP은 데이터만 지우는 것이 아니라
테이블 자체를 삭제하는 문장이다.

즉,

  • DELETE
    → 행 삭제

  • TRUNCATE
    → 데이터 전체 비우기

  • DROP
    → 테이블 자체 삭제

이렇게 구분하면 된다.

처음에는 얼마나 빠른지보다, 무엇을 지우는 문장인지를 먼저 구분하는 것이 더 중요하다.



세 문장을 함께 보면 이렇게 정리된다

이 파트는 문장이 세 개라서 많아 보이지만,
실제로는 역할이 아주 선명하게 갈린다.

  • INSERT
    → 새 행 넣기

  • UPDATE
    → 기존 행 값 바꾸기

  • DELETE
    → 기존 행 지우기

즉, 셋 다 행 데이터를 다루는 문장이라는 공통점이 있다.
하지만 하는 일은 각각 다르다.

그리고 이 파트에서 초보자가 꼭 같이 잡아야 하는 것은 이것이다.

실수는 대부분 WHERE를 빼먹을 때 난다.

  • UPDATE에서 WHERE가 없으면 전체 수정
  • DELETE에서 WHERE가 없으면 전체 삭제

또 WHERE가 있어도 조건에 맞는 행이 여러 개면
그 행들이 한꺼번에 바뀌거나 지워질 수 있다.

이 기준만 확실히 잡아도 훨씬 안전하게 읽을 수 있다.


헷갈리기 쉬운 부분

첫째, INSERT는 새 데이터를 추가하는 문장이다.
기존 데이터를 바꾸는 문장이 아니다.

둘째, UPDATE는 기존 값을 수정하는 문장이다.
이때 WHERE가 없으면 전체 행이 바뀔 수 있다.

셋째, DELETE는 행 데이터를 지우는 문장이다.
테이블 구조 자체를 없애는 것은 아니다.

넷째, DELETE, TRUNCATE, DROP은 모두 지우는 느낌이 있지만 서로 다르다.

  • DELETE → 행 삭제
  • TRUNCATE → 테이블 내용 전체 비우기
  • DROP → 테이블 자체 삭제

다섯째, INSERT에서 열 이름을 생략하면
값의 순서와 개수를 정확히 맞춰야 한다.

여섯째, EMP처럼 컬럼이 많은 테이블은
처음부터 열 이름을 함께 쓰는 편이 훨씬 안전하다.


짧게 흐름으로 다시 보기

INSERT
→ 새 행 추가하기


UPDATE
→ 기존 행 값 수정하기


DELETE
→ 기존 행 삭제하기

즉, 이 파트의 핵심은
이미 만들어진 테이블 안의 행 데이터를 직접 바꾸는 세 가지 방법을 구분해서 이해하는 것이다.




2. MySQL 데이터 형식

개념

테이블을 만들기 전에 먼저 정해야 하는 것이 있다.
바로 각 컬럼에 어떤 종류의 값을 저장할 것인가다.

이때 정하는 것이 데이터 형식이다.
같은 값처럼 보여도 어떤 형식으로 저장하느냐에 따라 저장 방식이 달라지고, 나중에 조회하거나 계산하거나 비교할 때의 동작도 달라진다. MySQL은 숫자, 문자, 날짜·시간, 기타 형식처럼 여러 Data Type을 지원하고, 이를 이해해야 테이블을 효율적으로 만들고 데이터를 자연스럽게 다룰 수 있다.


예를 들어 이런 차이가 있다.

  • 점수는 더하고 평균을 내야 하니까 숫자 형식
  • 이름은 글자 자체가 중요하니까 문자 형식
  • 가입일은 날짜 계산이 필요하니까 날짜 형식

즉, 데이터 형식은
값을 담는 그릇을 미리 정해 두는 것이라고 이해하면 된다.



데이터 형식을 왜 먼저 알아야 하는가

처음에는 그냥 값을 넣으면 되는 것처럼 보일 수 있다.
하지만 실제로는 어떤 형식으로 저장하느냐가 이후 작업에 큰 영향을 준다.

예를 들어 숫자를 문자처럼 저장하면
합계를 구하거나 크기를 비교할 때 어색해질 수 있다.
반대로 이름이나 전화번호 같은 값을 숫자로 생각하면,
그 값의 내용보다 계산 쪽으로 잘못 이해될 수 있다.


날짜도 마찬가지다.
날짜를 날짜 형식으로 저장하면 연도, 월, 일을 쉽게 꺼낼 수 있고,
며칠 차이인지 계산하는 것도 자연스럽다.
그런데 날짜를 그냥 문자처럼 저장하면 이런 작업이 훨씬 불편해질 수 있다.

즉, 데이터 형식은 단순히 저장만을 위한 설정이 아니라
나중에 데이터를 제대로 다루기 위한 준비 작업이다.



MySQL 데이터 형식은 크게 이렇게 나눈다

처음부터 형식 이름을 전부 외우려고 하면 부담스럽다.
그래서 먼저 큰 분류부터 잡는 것이 좋다.

MySQL 데이터 형식은 크게 아래처럼 보면 된다.

  • 숫자 데이터 형식
  • 문자 데이터 형식
  • 날짜와 시간 데이터 형식
  • 기타 데이터 형식

즉, 처음에는
이 값이 숫자인가, 문자인가, 날짜인가
이 기준부터 잡으면 된다. MySQL 데이터 형식은 자주 쓰는 형식을 중심으로 숫자, 문자, 날짜·시간, 기타 형식으로 나누어 이해하면 된다.



1. 숫자 데이터 형식

숫자 데이터 형식은 숫자를 저장할 때 사용하는 형식이다.
예를 들어 나이, 수량, 점수, 가격, 재고 수 같은 값이 여기에 들어간다.

숫자 형식을 따로 두는 이유는 단순하다.
숫자는 나중에 더하기, 평균 구하기, 크기 비교하기, 정렬하기 같은 작업을 자주 하기 때문이다.

숫자 데이터 형식 표

데이터 형식바이트 수숫자 범위설명
BIT(N)N/8-1~64bit를 표현, b'0000' 형식으로 표현
TINYINT1-128 ~ 127정수
SMALLINT2-32,768 ~ 32,767정수
MEDIUMINT3-8,388,608 ~ 8,388,607정수
INT, INTEGER4약 -21억 ~ +21억정수
BIGINT8약 -900경 ~ +900경정수
FLOAT4-3.40E+38 ~ 1.17E-38소수점 아래 7자리까지 표현
DOUBLE, REAL8-1.22E-308 ~ 1.79E+308소수점 아래 15자리까지 표현
DECIMAL(m,d), NUMERIC(m,d)5~17-10^38+1 ~ +10^38-1전체 자릿수 m과 소수점 이하 자릿수 d를 직접 지정하는 숫자형

숫자 형식은 이렇게 이해하면 된다

정수는 보통 INT부터 떠올리면 된다

나이, 개수, 번호처럼 소수점이 필요 없는 값은
먼저 INT를 떠올리면 된다.

예를 들어

  • 학생 점수
  • 게시글 번호
  • 주문 개수

이런 값은 대부분 정수로 다루면 된다.

더 큰 숫자가 필요하면 BIGINT를 생각하면 된다

보통은 INT로도 충분하지만,
아주 큰 번호나 아주 큰 범위의 값이 필요하면 BIGINT를 쓸 수 있다.

즉, 정수 형식은 기본적으로
얼마나 큰 숫자까지 담아야 하는가의 차이로 보면 된다.

소수는 FLOAT, DOUBLE, DECIMAL을 떠올리면 된다

소수점이 필요한 값은 정수 형식으로는 부족하다.

예를 들어

  • 몸무게
  • 별점 평균
  • 금액 계산
  • 할인율

같은 값은 소수점이 필요할 수 있다.

DECIMAL은 돈처럼 정확한 자릿수가 중요할 때 더 잘 어울린다

소수라서 전부 비슷해 보일 수 있지만 차이가 있다.

예를 들어 DECIMAL(5,2)는
전체 자릿수를 5자리로 하고,
그중 소수점 아래를 2자리로 하겠다는 뜻이다.

즉, 숫자 형식을 볼 때는 처음에 이렇게 생각하면 된다.

  • 소수점이 없으면 정수
  • 소수점이 있으면 실수
  • 정확한 자릿수가 중요하면 DECIMAL



2. 문자 데이터 형식

문자 데이터 형식은 글자나 문자열을 저장할 때 사용한다.
예를 들어 이름, 주소, 아이디, 상품명, 이메일, 전화번호 같은 값이 여기에 들어간다.

여기서 자주 헷갈리는 부분이 있다.
숫자처럼 생겼다고 해서 무조건 숫자 형식으로 저장하는 것은 아니라는 점이다.

예를 들어 전화번호를 보자.
01012345678
이 값은 숫자처럼 보이지만,
보통 더하거나 평균을 낼 값이 아니다.
즉, 계산 대상이 아니라 내용 자체가 중요한 값이다.
이런 값은 문자 형식으로 다루는 것이 훨씬 자연스럽다.

문자 데이터 형식 표

데이터 형식바이트 수설명
CHAR(n)1~255고정길이 문자열. n을 1부터 255까지 지정. 그냥 CHAR만 쓰면 CHAR(1)과 동일
VARCHAR(n)1~65535가변길이 문자열. 길이가 달라질 수 있는 일반 문자열 저장에 가장 많이 사용
BINARY(n)1~255고정길이 이진 데이터 값
VARBINARY(n)1~255가변길이 이진 데이터 값
TINYTEXT1~255최대 255 크기의 TEXT 데이터 값
TEXT1~65535일반적인 긴 문자열 저장
MEDIUMTEXT1~16777215더 큰 TEXT 데이터 값
LONGTEXT1~4294967295최대 약 4GB 크기의 TEXT 데이터 값
TINYBLOB1~255최대 255 크기의 BLOB 데이터 값
BLOB1~65535일반적인 BLOB 데이터 값
MEDIUMBLOB1~16777215더 큰 BLOB 데이터 값
LONGBLOB1~4294967295최대 약 4GB 크기의 BLOB 데이터 값
ENUM(값들...)1 또는 2미리 정해 둔 값 중 하나를 저장. 최대 65535개의 열거형 데이터 값
SET(값들...)1, 2, 3, 4, 8미리 정해 둔 값들 중 여러 개를 함께 저장 가능. 최대 64개의 서로 다른 데이터 값

문자 형식은 이렇게 이해하면 된다

CHAR는 길이가 고정된 문자열

CHAR는 길이를 미리 정해 두고 쓰는 형식이다.
항상 길이가 거의 같거나, 길이가 딱 정해져 있는 값에 더 잘 어울린다.

예를 들어 성별 코드처럼
항상 길이가 짧고 일정한 값은 CHAR로 생각해 볼 수 있다.

VARCHAR는 길이가 달라질 수 있는 문자열

VARCHAR는 실제 문자열 길이에 따라 유연하게 쓰는 형식이다.
이름, 주소, 이메일처럼 길이가 사람마다 달라질 수 있는 값에 더 자연스럽다.

초보자 기준으로는

  • 길이가 딱 정해진 느낌이면 CHAR
  • 길이가 달라질 수 있으면 VARCHAR

이렇게 먼저 구분하면 된다.

TEXT는 긴 글을 저장할 때

짧은 이름이나 주소가 아니라
소개글, 본문, 후기처럼 내용이 길어질 수 있는 경우에는 TEXT 계열을 생각하면 된다.

LONGTEXT는 아주 긴 글

장문의 문서, 긴 본문처럼
텍스트 크기가 매우 큰 경우를 떠올리면 된다.

BLOB 계열은 파일 같은 바이너리 데이터

표에는 함께 들어가 있지만, BLOB 계열은 글자를 저장하는 형식이 아니라
이미지, 파일, 영상 같은 바이너리 데이터를 저장하는 쪽에 더 가깝다.

즉, TEXT 계열은 긴 글,
BLOB 계열은 글자가 아닌 큰 파일 데이터라고 구분하면 된다. LONGTEXT, LONGBLOB은 큰 데이터를 저장하기 위한 LOB 형식이고, LONGTEXT는 큰 텍스트, LONGBLOB은 큰 바이너리 데이터 저장용으로 설명된다.

ENUM은 정해진 값 중 하나를 고를 때

예를 들어

  • 상태가 신청, 진행중, 완료
  • 등급이 A, B, C

처럼 미리 정해진 값 중 하나만 들어가야 하는 경우에 어울린다.

SET은 여러 값을 함께 선택할 때

SET은 미리 정해 놓은 값들 중에서
하나만이 아니라 여러 개를 함께 저장할 수 있는 형식이다.

즉, 문자 형식은 단순히 글자를 저장하는 것뿐 아니라
값의 성격이 계산용인지, 내용용인지, 긴 글인지, 정해진 선택지인지까지 함께 생각해야 한다.



3. 날짜와 시간 데이터 형식

날짜와 시간 데이터 형식은
말 그대로 날짜, 시간, 날짜+시간 값을 저장할 때 사용한다.

예를 들어

  • 회원 가입일
  • 주문 날짜
  • 작성 시간
  • 입사일
  • 예약 시간

같은 값이 여기에 들어간다.

날짜와 시간 데이터 형식 표

데이터 형식바이트 수설명
DATE3날짜만 저장, 'YYYY-MM-DD' 형식 사용
TIME3시간만 저장, 'HH:MM:SS' 형식 사용
DATETIME8날짜와 시간을 함께 저장, 'YYYY-MM-DD HH:MM:SS' 형식 사용
TIMESTAMP4날짜와 시간을 저장하며 상황에 따라 시간대 설정과 함께 다뤄질 수 있음
YEAR1연도만 저장, 'YYYY' 형식 사용

날짜와 시간 형식은 이렇게 이해하면 된다

DATE

날짜만 저장할 때 사용한다.
예를 들어 2026-04-01처럼
연-월-일만 필요할 때 어울린다.

TIME

시간만 저장할 때 사용한다.
예를 들어 12:35:29처럼
시-분-초만 필요할 때 쓴다.

DATETIME

날짜와 시간을 함께 저장할 때 사용한다.
예를 들어 가입 시각, 결제 시각처럼
언제 발생했는지를 정확히 남기고 싶을 때 자연스럽다.

TIMESTAMP

TIMESTAMP도 날짜와 시간을 저장하는 형식이다.
처음에는 DATETIME과 비슷하게 보이는데, 상황에 따라 시간대 설정과 함께 다뤄질 수 있다는 정도만 먼저 알고 있으면 된다.

즉, 초보자 기준에서는
DATETIME과 함께 날짜+시간 저장용 형식이라는 감각을 먼저 잡는 것이 중요하다.

YEAR

연도만 따로 저장할 때 사용한다.
예를 들어 출생연도, 입학연도처럼
연도 정보만 중요할 때 쓸 수 있다.

즉, 날짜·시간 형식은 문자처럼 보이는 값을 저장하는 것이 아니라
나중에 날짜와 시간처럼 다루기 위해 저장하는 형식이라고 이해하면 된다. DATE, TIME, DATETIME, TIMESTAMP, YEAR은 날짜·시간 관련 데이터를 저장하기 위한 대표 형식이다.



4. 기타 데이터 형식

기타 데이터 형식은 숫자, 문자, 날짜·시간 형식만으로는 다루기 어려운 값을 저장할 때 사용하는 형식이다.

즉, 기본적인 형식만으로는 부족할 때 등장하는
특수 목적용 형식이라고 보면 된다.

기타 데이터 형식 표

데이터 형식바이트 수설명
GEOMETRYN/A선, 점, 다각형 같은 공간 데이터를 저장하고 조작
JSON8JSON(JavaScript Object Notation) 문서를 저장

이 부분은 처음부터 깊게 들어갈 필요는 없다.
다만 MySQL에는 일반 숫자, 문자, 날짜 말고도
이런 특수 목적용 형식이 있다는 정도는 알고 있으면 충분하다. GEOMETRY, JSON 같은 형식은 일반적인 값 저장이 아니라 조금 더 특별한 목적을 가진 형식으로 보면 된다.





형 변환

개념

값을 다루다 보면 원래 형식 그대로만 쓰는 것이 아니라,
다른 형식으로 바꾸어 사용해야 할 때가 있다.
이것이 형 변환이다.

예를 들어 문자처럼 저장된 값을 숫자로 바꿔 계산하거나,
숫자를 문자로 바꿔서 이어 붙일 수도 있다.

즉, 형 변환은
값의 종류를 상황에 맞게 바꾸어 사용하는 것이다. CAST()와 CONVERT()는 대표적인 형 변환 함수이고, 함수 없이 자동으로 형이 바뀌는 경우는 암시적 형 변환으로 본다.


1. 명시적 형 변환

직접 함수를 써서 형식을 바꾸는 것을
명시적 형 변환이라고 한다.

대표적인 문법은 아래와 같다.

CAST(expression AS 데이터형식[(길이)])
CONVERT(expression, 데이터형식[(길이)])

즉, 내가 직접
“이 값을 숫자로 바꿔라”,
“이 값을 문자로 바꿔라”
라고 지정하는 방식이다.

예를 들어 평균값을 구하면 결과가 소수로 나올 수 있다.
그런데 그 값을 정수처럼 보고 싶다면
CAST()나 CONVERT()를 써서 형식을 바꿀 수 있다.

예제에서는 buytbl의 평균 구매 개수를 구한 뒤
그 결과를 정수형으로 바꾸는 흐름을 보여준다. CAST(), CONVERT()는 가장 일반적인 데이터 형 변환 함수이고, 평균 구매 개수 예제로도 설명된다.

핵심은
CAST()와 CONVERT()가 형식을 직접 지정해서 바꾸는 함수라는 점이다.



2. 암시적 형 변환

형 변환은 항상 직접 쓰는 것만 있는 것은 아니다.
경우에 따라서는 MySQL이 상황에 맞게 자동으로 형을 바꾸어 처리하기도 한다.

이것을 암시적 형 변환이라고 한다.

이 예제에서는

  • 문자와 문자를 더할 때 숫자로 바뀌어 계산되기도 하고
  • 문자열을 연결할 때는 문자처럼 처리되기도 하고
  • 숫자와 문자를 비교할 때 자동으로 숫자처럼 해석되기도 한다

즉, 내가 직접 “바꿔라”라고 쓰지 않아도
MySQL이 문맥을 보고 알아서 형을 바꾸는 경우가 있는 것이다. CAST()나 CONVERT()를 사용하지 않고 형이 변하는 것을 암시적 형 변환으로 이해하면 된다.


초보자 입장에서는 이걸 이렇게 기억하면 된다.

  • 직접 바꾸면 명시적 형 변환
  • 자동으로 바뀌면 암시적 형 변환

중요한 점은
이 자동 변환이 편리할 수도 있지만, 내가 생각한 방식과 다르게 동작할 수도 있다는 것이다.
그래서 형이 섞여 있는 값을 다룰 때는 결과가 어떻게 해석될지 한 번 더 확인하는 습관이 중요하다.



헷갈리기 쉬운 부분

첫째, 숫자처럼 보인다고 해서 모두 숫자 형식으로 저장하는 것은 아니다.
전화번호, 학번, 우편번호처럼 계산 대상이 아닌 값은 문자 형식이 더 자연스러울 수 있다.


둘째, 날짜는 문자처럼 저장할 수도 있어 보이지만,
나중에 날짜 계산과 비교를 하려면 날짜 형식으로 저장하는 편이 훨씬 자연스럽다.


셋째, 데이터 형식은 저장만을 위한 설정이 아니다.
조회, 계산, 비교, 정렬에도 직접 영향을 준다. 데이터 형식은 테이블 생성 시 열 이름과 함께 지정되고, 이후 데이터 활용 방식에도 직접 연결된다.


넷째, CAST()와 CONVERT()는 직접 형을 바꾸는 함수다.
반대로 함수 없이 자동으로 바뀌는 것은 암시적 형 변환이다.


다섯째, 처음부터 형식 이름을 전부 외우려 하지 말고
먼저 숫자인가, 문자인가, 날짜인가부터 구분하는 것이 더 중요하다.



짧게 흐름으로 다시 보기

숫자 데이터 형식
→ 계산하고 비교할 값 저장하기


문자 데이터 형식
→ 이름, 주소처럼 내용 자체가 중요한 값 저장하기


날짜와 시간 데이터 형식
→ 날짜 계산과 시간 처리가 필요한 값 저장하기


기타 데이터 형식
→ 특수 목적 데이터를 저장하기


형 변환
→ 필요할 때 값을 다른 형식으로 바꾸어 사용하기


즉, 이 파트의 핵심은
데이터를 어떤 종류의 값으로 저장할지 먼저 구분하고, 그에 맞는 형식을 선택하는 것이다.




3. 테이블 생성과 제약 조건

개념

앞에서 MySQL의 데이터 형식을 배웠다면, 이제는 그 형식을 실제 저장 구조에 붙여서 테이블을 만드는 단계로 넘어가게 된다.
이 구간의 핵심은 단순하다. 어떤 데이터를 저장할지 정하고, 그 데이터를 담을 열을 만들고, 각 열에 어떤 형식과 규칙을 줄지 정하는 것이다.

즉, 테이블 생성은 데이터를 넣기 전에 저장 틀을 먼저 설계하는 작업이다.


그리고 이때 같이 나오는 것이 제약 조건이다.
제약 조건은 아무 값이나 들어오지 못하게 막는 규칙이다. 같은 아이디가 두 번 들어오지 못하게 하거나, 부모 테이블에 없는 값을 자식 테이블이 참조하지 못하게 하거나, 비정상적인 값이 들어오지 못하게 제한하는 역할을 한다.

결국 이 구간은 테이블의 구조를 만들고, 그 구조 안에 어떤 규칙을 걸지 정하는 파트라고 보면 된다.


먼저 흐름부터 잡기

이 부분은 아래 순서로 이해하면 가장 덜 헷갈린다.

1. 데이터베이스를 만든다.
2. 사용할 데이터베이스를 선택한다.
3. 먼저 구조가 단순한 테이블을 하나 만들어 본다.
4. 그다음 필요하면 부모 테이블과 자식 테이블 구조를 본다.
5. 관계가 있는 경우 부모 테이블에 데이터를 먼저 넣는다.
6. 마지막으로 자식 테이블에 데이터를 넣는다.

즉, 처음에는 book처럼 혼자서도 이해할 수 있는 단순한 테이블로 테이블 생성 자체를 익히고,
그다음 외래 키가 붙는 관계형 구조는 usertbl, buytbl처럼 부모-자식 관계가 있는 예제로 이해하면 훨씬 덜 헷갈린다.



1. 테이블 생성

개념

테이블은 데이터를 표 형태로 저장하기 위한 구조다.
하지만 그냥 칸만 나누는 것이 아니다. 각 열마다 어떤 값이 들어올지, 그 값이 꼭 있어야 하는지, 중복이 가능한지까지 함께 정해야 한다.
그래서 테이블을 만들 때는 보통 아래 네 가지를 같이 본다.

  • 열 이름
  • 데이터 형식
  • NULL 허용 여부
  • 제약 조건

즉, 테이블 생성은 이름만 붙이는 작업이 아니라 데이터가 들어올 규칙까지 함께 정하는 작업이다.


핵심 특징

1) 테이블을 먼저 만들어야 INSERT가 가능하다

INSERT, UPDATE, DELETE 같은 DML은 테이블의 행을 다루는 명령이다.
그래서 테이블이 아직 없는데 데이터를 넣을 수는 없다.
먼저 CREATE DATABASE, CREATE TABLE 같은 DDL로 구조를 만든 다음에 데이터를 넣어야 한다.


2) 열 이름만 정하는 것이 아니라 데이터 형식도 같이 정한다

예를 들어 도서명은 문자형, 가격은 숫자형, 도서 분류 코드는 짧은 문자형처럼 정한다.
이때 형식이 맞지 않으면 나중에 데이터를 넣을 때 오류가 나거나 의도와 다른 값이 들어간다.
그래서 데이터 형식을 제대로 정하는 것이 테이블 설계의 출발점이다.


3) 열 목록을 생략한 INSERT는 순서가 정확히 맞아야 한다

INSERT INTO 테이블명 VALUES(...)처럼 열 이름을 생략하면, 괄호 안 값의 순서와 개수가 테이블 정의 순서와 정확히 같아야 한다.
이걸 모르면 값은 맞는데도 엉뚱한 열에 들어가거나 오류가 난다. 초보자일수록 이 부분을 자주 틀린다.


4) 자동 증가 열은 보통 직접 번호를 넣지 않는다

AUTO_INCREMENT가 걸린 열은 INSERT할 때 직접 값을 넣지 않거나 NULL을 넣으면 DB가 자동으로 1, 2, 3처럼 값을 채운다.
이 기능은 구매번호, 게시글번호처럼 각 행을 순서대로 구분해야 할 때 자주 사용한다.
AUTO_INCREMENT는 숫자형 열에 사용하고, 보통 PRIMARY KEY 또는 UNIQUE와 함께 쓴다.



코드 예제

예제: 데이터베이스 생성과 선택

CREATE DATABASE edudb;
USE edudb;

-- 1. edudb라는 데이터베이스를 만든다.
-- 2. 앞으로 작업할 기본 데이터베이스를 edudb로 선택한다.

-- 출력결과
-- 데이터베이스 생성
-- 사용할 데이터베이스 변경

이 코드는 가장 바깥 저장소를 먼저 준비하는 예제다.
테이블은 데이터베이스 안에 만들어지므로, 보통 CREATE DATABASE와 USE가 먼저 온다.


예제: book 생성

CREATE TABLE book (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(40),
    price INT,
    kind CHAR(3)
);

DESC book;

-- 1. book이라는 이름의 테이블을 만든다.
-- 2. id는 각 행을 구분하는 식별값이므로 PRIMARY KEY를 준다.
-- 3. id는 AUTO_INCREMENT를 설정해서 데이터가 들어갈 때 번호가 자동으로 증가하게 한다.
-- 4. title은 도서명을 저장하는 열이므로 VARCHAR(40)으로 만든다.
-- 5. price는 가격을 저장하는 숫자 열이므로 INT로 만든다.
-- 6. kind는 도서 분류 코드를 저장하므로 CHAR(3)으로 만든다.

-- 출력결과
-- book 생성 완료
-- book 테이블 구조 확인

이 코드는 테이블을 만들 때 열 이름, 데이터 형식, PRIMARY KEY, AUTO_INCREMENT가 실제로 어떻게 들어가는지 보여 주는 가장 기본적인 예제다.
특히 id는 단순한 숫자 열이 아니라, 각 행을 구분하는 기준이면서 데이터가 추가될 때 자동으로 번호가 붙는 열이라는 점을 같이 봐야 한다.

위 이미지는 DESC book 결과를 보여 주는 부분이다.
즉, 테이블을 만든 뒤에는 바로 구조를 확인하면서 id, title, price, kind가 의도한 형식대로 생성되었는지 보는 흐름으로 이해하면 된다.


예제: book 데이터 입력

INSERT INTO book (title, price, kind)
VALUES
('자바의 정석', 36000, 'b01'),
('모던 자바스크립트 핵심 가이드', 19800, 'b02'),
('그림과 실습으로 배우는 도커', 28000, 'b05'),
('MySQL로 배우는 데이터베이스 개론과 실습', 27000, 'b04'),
('이것이 스프링부트다', 36000, 'b02');

SELECT * FROM book;

-- 1. id는 AUTO_INCREMENT 열이므로 직접 값을 넣지 않는다.
-- 2. title, price, kind 열에 맞춰 도서 데이터를 저장한다.
-- 3. INSERT가 끝난 뒤 SELECT로 실제 저장 결과를 확인한다.

-- 출력결과
-- 도서 데이터 저장
-- book 테이블 조회

이 예제에서는 AUTO_INCREMENT가 걸린 id에 값을 직접 넣지 않는다는 점이 중요하다.
즉, 자동 번호 열이 있는 테이블은 보통 나머지 열만 지정해서 데이터를 넣는 방식으로 이해하면 된다.

위 이미지는 SELECT * FROM book 결과를 보여 주는 부분이다.
즉, 데이터 입력이 끝난 뒤에는 id가 자동으로 1, 2, 3처럼 붙었는지, 그리고 title, price, kind 값이 정상적으로 저장되었는지 함께 확인하는 흐름으로 보면 된다.



2. 제약 조건

개념

제약 조건은 데이터의 무결성을 지키기 위한 제한 규칙이다.
쉽게 말하면, 데이터가 틀어지지 않게 막아 주는 안전장치다.
예를 들어 아래 같은 상황을 막기 위해 제약 조건이 필요하다.

  • 같은 회원 아이디가 두 번 저장되는 경우
  • 부모 테이블에 없는 회원 아이디를 구매 테이블에 넣는 경우
  • 키에 음수 값이 들어가는 경우
  • 꼭 필요한 열이 비어 있는 경우

즉, 제약 조건은 귀찮은 문법이 아니라 데이터가 믿을 수 있는 상태를 유지하게 해 주는 장치다.



3. 주요 제약 조건

3-1. PRIMARY KEY

개념

PRIMARY KEY는 각 행을 구분하는 대표 열이다.
회원 테이블에서는 회원 아이디, 학생 테이블에서는 학번처럼 각 행을 유일하게 식별할 수 있는 값이 여기에 해당한다.

핵심 특징

  • 중복되면 안 된다.
  • NULL이 들어가면 안 된다.
  • 각 행을 구분할 수 있어야 한다.

즉, PRIMARY KEY는 중복 불가 + 빈 값 불가를 동시에 만족해야 한다.


3-2. FOREIGN KEY

개념

FOREIGN KEY는 두 테이블 사이의 관계를 연결하는 키다.
자식 테이블의 값이 부모 테이블의 값을 참조하도록 만들어서, 서로 관련 있는 데이터가 엉키지 않게 해 준다.

핵심 특징

  • 자식 테이블이 부모 테이블의 값을 참조한다.
  • 참조되는 부모 열은 PRIMARY KEY이거나 UNIQUE여야 한다.
  • 부모에 없는 값은 자식에 넣을 수 없다.
  • 부모가 먼저 있고, 자식이 나중에 따라와야 한다.

즉, FOREIGN KEY는 값 복사가 아니라 관계 연결 규칙이다. buytbl이 usertbl 전체를 들고 있는 것이 아니라, usertbl의 userID를 기준으로 누구의 구매인지 연결하는 것이다.

참고

외래 키에는 ON DELETE CASCADE, ON UPDATE CASCADE 같은 옵션도 줄 수 있다.
이 옵션은 부모 데이터가 바뀌거나 삭제될 때 자식 테이블에도 그 변경을 자동으로 반영하도록 하는 기능이다.


3-3. UNIQUE

개념

UNIQUE는 중복되지 않는 유일한 값을 요구하는 제약 조건이다.
대표적으로 이메일처럼, 들어오는 값은 중복되면 안 되지만 테이블의 대표 식별자로 쓰지는 않는 열에 어울린다.

핵심 특징

  • 중복은 허용하지 않는다.
  • PRIMARY KEY와 비슷하지만 NULL은 허용할 수 있다.
  • NULL은 여러 개가 들어와도 상관없다.

즉, UNIQUE는 유일해야 하지만 대표 키까지는 아닌 값에 걸기 좋은 규칙이다.


3-4. CHECK

개념

CHECK는 입력되는 값이 특정 조건을 만족하는지 검사하는 제약 조건이다.
형식만 맞는다고 통과시키는 것이 아니라, 값의 내용이 조건에 맞는지도 확인한다.
예를 들어 키는 음수가 될 수 없고, 출생년도는 너무 비정상적인 값이면 안 되게 만들 수 있다.

MySQL에서는 8.0.16부터 지원한다.


3-5. DEFAULT

개념

DEFAULT는 값을 따로 넣지 않았을 때 자동으로 들어갈 기본값이다.
매번 같은 값을 직접 입력하는 번거로움을 줄이고, 값이 비는 상황도 줄여 준다.


3-6. NULL 과 NOT NULL

개념

NULL은 공백 문자열 ''이나 숫자 0과 다르다.
NULL은 아무 것도 없음, 즉 값이 존재하지 않는 상태를 뜻한다.
그래서 꼭 필요한 열이라면 NOT NULL을 걸어서 비워 둘 수 없게 해야 한다.
PRIMARY KEY가 걸린 열은 자동으로 NOT NULL 성격을 가진다.


코드 예제

예제: 여러 제약 조건을 함께 걸기

CREATE TABLE membertbl (
    userID CHAR(8) PRIMARY KEY,
    email VARCHAR(50) UNIQUE,
    birthYear INT CHECK (birthYear >= 1900),
    height SMALLINT CHECK (height >= 0),
    grade CHAR(1) DEFAULT 'B'
);

-- 1. userID는 PRIMARY KEY라서 중복과 NULL을 허용하지 않는다.
-- 2. email은 UNIQUE라서 같은 값이 두 번 들어오면 안 된다.
-- 3. birthYear, height는 CHECK로 이상한 값이 들어오지 못하게 한다.
-- 4. grade는 값을 생략하면 기본값으로 'B'가 들어간다.

-- 출력결과
-- membertbl 생성 완료

이 예제는 PRIMARY KEY, UNIQUE, CHECK, DEFAULT가 실제 테이블 정의 안에서 어떻게 보이는지 한 번에 보여준다.
즉, 제약 조건은 각각 따로 외우는 것이 아니라 열 뒤에 붙는 규칙으로 함께 읽어야 이해가 된다.



4. 틀리기 쉬운 예시

FOREIGN KEY는 단순한 book 예제로는 잘 안 보이므로, 여기부터는 관계형 예제로 설명한다

예제: PRIMARY KEY 중복

INSERT INTO usertbl VALUES('KBS', '다른사람', 1990, '서울', '010', '9999999', 180, '2024-1-1');

-- 1. userID는 PRIMARY KEY다.
-- 2. 이미 들어 있는 'KBS'를 다시 넣으려고 하면 중복이 된다.

-- 출력결과
-- 오류 발생
-- 이유: PRIMARY KEY는 중복을 허용하지 않기 때문

예제: 없는 회원 아이디를 FOREIGN KEY로 넣기

INSERT INTO buytbl VALUES(NULL, 'JYP', '모니터', '전자', 200, 1);

-- 1. buytbl의 userID는 usertbl의 userID를 참조한다.
-- 2. usertbl에 'JYP'가 없는데 buytbl에 넣으려고 하면 참조 기준이 없다.

-- 출력결과
-- 오류 발생
-- 이유: FOREIGN KEY는 부모 테이블에 실제 존재하는 값만 참조할 수 있기 때문

예제: PRIMARY KEY에 NULL 넣기

INSERT INTO usertbl VALUES(NULL, '홍길동', 2000, '서울', '010', '1234567', 175, '2024-1-1');

-- 1. userID는 PRIMARY KEY다.
-- 2. PRIMARY KEY는 NULL을 허용하지 않는다.

-- 출력결과
-- 오류 발생
-- 이유: PRIMARY KEY는 각 행을 구분하는 값이어야 하므로 비어 있을 수 없기 때문

이런 예시는 꼭 같이 봐야 한다.
되는 코드만 보면 이해한 것 같지만, 제약 조건은 결국 무엇을 막는 규칙인지까지 알아야 제대로 잡힌다.



헷갈리기 쉬운 부분

1. PRIMARY KEY와 UNIQUE는 비슷하지만 같지 않다

둘 다 중복을 막는다는 점은 비슷하다.
하지만 PRIMARY KEY는 각 행을 대표해서 구분하는 기준이고 NULL도 허용하지 않는다.
반면 UNIQUE는 중복만 막고 NULL은 허용할 수 있다. 그래서 대표 식별자면 PRIMARY KEY, 유일하기만 하면 UNIQUE라고 구분해서 보면 된다.


2. NULL은 공백도 아니고 0도 아니다

NULL은 값이 없는 상태다.
공백 문자열은 문자열이 들어 있는 것이고, 0은 숫자가 들어 있는 것이다.
셋은 비슷해 보여도 전혀 다르다.


3. 부모 테이블을 먼저 만들고 먼저 넣어야 한다

자식 테이블은 부모 값을 참조해야 하므로 부모가 먼저 있어야 한다.
그래서 usertbl을 먼저 만들고, buytbl을 나중에 만든다. 데이터도 회원 정보를 먼저 넣고 구매 정보를 나중에 넣는다. 이 순서가 틀리면 왜 오류가 나는지 이해하기 어렵다.


4. 부모 테이블을 먼저 삭제할 수 없는 이유도 같다

외래 키가 걸려 있는 상태에서는 부모 테이블을 먼저 삭제할 수 없다.
구매 테이블이 회원 테이블을 참조하고 있는데 회원 테이블을 먼저 지워 버리면 참조 기준이 사라지기 때문이다.
그래서 보통은 자식 테이블을 먼저 정리하고 부모 테이블을 나중에 다룬다.


5. AUTO_INCREMENT 열에 들어간 NULL은 일반적인 NULL과 느낌이 다르다

보통 NULL은 값이 없다는 뜻이지만, AUTO_INCREMENT 열에 넣은 NULL은 자동 번호를 생성하라는 의미로 동작한다.
그래서 문법만 외우지 말고, 어떤 열에 넣은 NULL인지까지 같이 봐야 한다.




4. 테이블 삭제와 ALTER TABLE

개념

앞에서 테이블 생성과 제약조건을 배웠다면, 이제는 이미 만들어 둔 테이블을 지우거나 수정하는 방법으로 넘어가게 된다.
테이블은 한 번 만들고 끝나는 것이 아니다. 필요 없어지면 삭제할 수도 있고, 중간에 열을 추가하거나 이름을 바꾸거나 제약조건을 수정해야 할 수도 있다.

이때 핵심이 되는 명령이 DROP TABLE과 ALTER TABLE이다.

  • DROP TABLE : 테이블 자체를 삭제
  • ALTER TABLE : 테이블 구조를 수정
    이 둘은 모두 DDL에 속하므로 실행하면 바로 반영된다.
    즉, 단순 조회가 아니라 테이블 구조 자체를 건드리는 명령이라는 점을 먼저 잡고 가야 한다.


먼저 흐름부터 잡기

이 파트는 아래 차이만 정확히 구분하면 이해가 쉬워진다.

  • DELETE : 행 데이터를 삭제
  • TRUNCATE : 테이블 구조는 남기고 전체 데이터를 비움
  • DROP TABLE : 테이블 자체를 삭제
  • ALTER TABLE : 테이블 구조를 수정

즉,
데이터만 지우는지,
구조는 남기는지,
테이블까지 없애는지를 먼저 구분해야 한다.



1. 테이블 삭제

개념

테이블 삭제는 데이터 몇 줄만 지우는 것이 아니라, 테이블 자체를 없애는 작업이다.
그래서 한 번 삭제하면 그 안에 있던 데이터, 열 구조, 제약조건도 함께 사라진다.

여기서 가장 먼저 구분해야 하는 것이 DELETE와 DROP TABLE의 차이다.

  • DELETE는 행 삭제
  • DROP TABLE은 테이블 삭제

즉, DELETE는 테이블은 남기고 내용물만 지우는 것이고,
DROP TABLE은 테이블 자체를 없애는 것이다.


핵심 특징

1) 외래 키 관계가 있으면 아무 테이블이나 먼저 삭제할 수 없다

외래 키가 걸린 구조에서는 참조당하는 쪽이 부모 테이블, 참조하는 쪽이 자식 테이블이다.

이때 자식 테이블이 아직 부모 테이블을 참조하고 있으면, 부모 테이블을 먼저 삭제할 수 없다.
예를 들어 buytbl이 usertbl을 참조하고 있다면, usertbl을 먼저 삭제하면 안 된다.
반드시 자식 테이블을 먼저 정리한 뒤 부모 테이블을 나중에 삭제해야 한다.


2) 삭제 순서는 보통 자식 -> 부모다

데이터를 넣을 때는 보통 부모 -> 자식 순서로 간다.
반대로 삭제할 때는 자식 -> 부모 순서로 가는 경우가 많다.

이유는 자식이 부모를 참조하고 있기 때문이다.
자식이 남아 있는데 부모를 먼저 지우면 참조 관계가 깨진다.


3) 여러 테이블을 한 번에 삭제할 수도 있다

여러 테이블을 한 번에 삭제하는 문법도 있다.
또 IF EXISTS를 붙이면 해당 테이블이 있을 때만 삭제하도록 만들 수 있다.

다만 여러 테이블을 함께 지울 때도, 머릿속에서는 여전히 외래 키 관계와 삭제 순서를 먼저 떠올려야 한다.
즉, 문법은 한 줄이어도 생각은 자식 -> 부모 순서로 해야 한다.


4) DELETE, TRUNCATE, DROP TABLE은 의미가 다르다

이 셋은 모두 “지운다”는 느낌이 있지만 실제로는 다르다.

DELETE는 조건에 맞는 행을 지우고,
TRUNCATE는 테이블 구조를 남긴 채 전체 데이터를 비우며,
DROP TABLE은 테이블 자체를 없앤다.


그래서 테이블은 계속 사용할 건데 데이터만 전부 비우고 싶다면 TRUNCATE가 더 맞고,
테이블 자체가 더 이상 필요 없으면 DROP TABLE이 맞다.


코드 예제

예제: 테이블 자체 삭제

DROP TABLE buytbl;

-- 실행결과
-- 테이블 삭제 완료

이 코드는 buytbl 테이블 자체를 삭제하는 예제다.
데이터만 비우는 것이 아니라 테이블 구조까지 함께 사라진다.


예제: 존재할 때만 삭제

DROP TABLE IF EXISTS buytbl;

-- 실행결과
-- 테이블 삭제 완료 또는 그대로 넘어감

같은 삭제 명령을 여러 번 실행할 때 유용하다.
이미 없는 테이블 때문에 에러가 나는 상황을 줄일 수 있다.


예제: 여러 테이블 삭제

DROP TABLE IF EXISTS buytbl, usertbl;

-- 실행결과
-- 여러 테이블 삭제 완료

이 코드는 여러 테이블을 한 번에 삭제하는 형태다.
다만 실제로는 buytbl처럼 자식 테이블을 먼저 생각하고, usertbl 같은 부모 테이블을 나중에 생각하는 흐름으로 이해하는 것이 좋다.



2. ALTER TABLE

개념

ALTER TABLE은 이미 만들어져 있는 테이블의 구조를 수정할 때 사용하는 명령이다.
처음 설계를 완벽하게 끝내면 좋지만, 실제로는 중간에 열을 추가해야 하거나, 이름을 바꿔야 하거나, 제약조건을 수정해야 하는 일이 생긴다.

이럴 때 기존 테이블을 다시 만들지 않고 구조만 손보는 방식이 ALTER TABLE이다.
즉, ALTER TABLE은 열을 추가하거나 삭제하고, 이름이나 자료형을 바꾸고, 제약조건을 수정할 때 사용하는 명령이라고 보면 된다.

즉, ALTER TABLE은
기존 테이블을 유지한 채 구조를 바꾸는 명령이라고 보면 된다.


핵심 특징

1) 열을 추가할 수 있다

새로운 정보를 저장해야 하면 열을 추가한다.
열을 추가하면 기본적으로 가장 뒤에 붙는다.
즉, 원래 있던 열 순서는 그대로 두고 새 열이 맨 끝에 추가된다고 이해하면 된다.


2) 열을 삭제할 수 있다

더 이상 필요 없는 열은 삭제할 수 있다.
하지만 그 열에 제약조건이 걸려 있으면 바로 삭제되지 않을 수 있다.

예를 들어 어떤 열이 PRIMARY KEY, FOREIGN KEY, UNIQUE 같은 제약조건과 연결되어 있으면,
먼저 관련 제약조건을 정리한 뒤 열을 삭제해야 한다.


3) 열 이름과 데이터 형식을 바꿀 수 있다

이미 만든 열이라도 이름을 바꾸거나 자료형을 바꿀 수 있다.
이때는 단순히 이름만 바꾸는 것이 아니라, 앞으로 이 열을 어떤 구조로 쓸지 다시 정의한다는 느낌으로 보면 된다.


4) 제약조건도 추가/삭제할 수 있다

ALTER TABLE은 열만 수정하는 명령이 아니다.
PRIMARY KEY, FOREIGN KEY, CHECK, DEFAULT 같은 제약조건도 수정할 수 있다.

즉, ALTER TABLE은
열 구조 수정 + 제약조건 수정을 함께 처리하는 명령이다.


코드 예제

예제: 열 추가

ALTER TABLE usertbl
ADD homepage VARCHAR(50);

-- 실행결과
-- 열 추가 완료

이 코드는 usertbl에 homepage 열을 추가하는 예제다.
기존 테이블은 그대로 두고, 새 정보만 더 저장할 수 있게 구조를 바꾼 것이다.


예제: 열 삭제

ALTER TABLE usertbl
DROP COLUMN homepage;

-- 실행결과
-- 열 삭제 완료

이 코드는 더 이상 필요 없는 열을 삭제하는 예제다.
다만 실제로는 해당 열에 제약조건이 연결되어 있으면, 그 제약조건부터 먼저 정리해야 한다.





예제: 열 이름과 데이터 형식 변경

ALTER TABLE usertbl
CHANGE COLUMN name uName VARCHAR(20) NULL;

-- 실행결과
-- 열 구조 변경 완료

이 코드에서 꼭 봐야 할 점은 앞의 name이 원래 열 이름이고, 뒤의 uName이 바뀔 열 이름이라는 점이다.
CHANGE COLUMN은 기존 열 이름을 먼저 쓰고, 그다음 새 열 이름을 쓴다.
초보자는 이 순서를 자주 반대로 이해하므로 같이 기억해야 한다.


예제: 기본 키 삭제가 바로 안 되는 경우

ALTER TABLE usertbl
DROP PRIMARY KEY;

-- 실행결과
-- 오류 발생

이 명령은 문법만 보면 기본 키를 삭제하는 코드다.
하지만 usertbl.userID가 buytbl의 FOREIGN KEY 기준으로 연결되어 있다면 바로 실행되지 않을 수 있다.

즉, 먼저 자식 테이블 쪽 FOREIGN KEY를 정리한 뒤 부모 테이블의 PRIMARY KEY를 삭제해야 한다.
이건 문법 문제가 아니라, 테이블 사이의 관계 때문에 생기는 문제다.



헷갈리기 쉬운 부분

1) DELETE와 DROP TABLE은 전혀 다르다

둘 다 삭제 명령처럼 보여도 의미가 다르다.

  • DELETE : 행 삭제
  • DROP TABLE : 테이블 삭제

즉, DELETE를 해도 테이블은 남아 있고 다시 데이터를 넣을 수 있다.
하지만 DROP TABLE을 하면 테이블 이름 자체가 사라진다.


2) 부모 테이블을 먼저 삭제하면 안 되는 경우가 많다

외래 키가 걸려 있으면 보통 삭제 순서는 자식 -> 부모다.
데이터를 넣을 때의 순서와 반대로 생각해야 한다.

그래서 삭제 명령을 보기 전에 먼저 테이블 관계부터 떠올리는 습관이 중요하다.


3) ALTER TABLE은 열만 수정하는 명령이 아니다

초보자는 ALTER TABLE을 보면 “열 추가하는 명령” 정도로 생각하기 쉽다.
하지만 실제로는 열 추가, 열 삭제, 이름 변경, 형식 변경, 제약조건 수정까지 모두 포함한다.
즉, 기존 테이블 구조를 손보는 거의 모든 작업을 맡는다고 보면 된다.


4) 제약조건이 있으면 바로 삭제되지 않을 수 있다

열을 지우거나 기본 키를 없애고 싶어도, 그 열이 다른 테이블과 연결되어 있으면 바로 안 된다.
이건 문법 문제가 아니라 관계 문제다.

특히 기본 키가 다른 테이블에서 외래 키로 참조되고 있으면,
먼저 참조 관계를 정리해야 한다는 점을 꼭 기억해야 한다.




5. 뷰

개념

뷰는 자주 사용하는 조회 결과를 이름 붙여 만든 조회용 객체다.
사용할 때는 테이블처럼 조회할 수 있어서, 처음에는 테이블처럼 보이는 조회용 객체라고 이해하면 된다. 한 번 만들어 두면 원본 테이블을 매번 길게 조회하지 않고, 뷰 이름으로 같은 결과를 다시 사용할 수 있다.

쉽게 말하면,
원본 데이터를 새로 저장하는 것이 아니라 보고 싶은 결과를 편하게 다시 꺼내 보기 위해 만든 객체에 가깝다.

예를 들어 직원 정보와 부서 정보를 함께 보기 위해 매번 조인을 써야 한다면,
그 조회 결과를 뷰로 만들어 두고 나중에는 뷰 이름만 조회하면 된다.


왜 필요한가

뷰를 사용하는 이유는 크게 두 가지다.

첫째, 복잡한 조회를 단순하게 만들기 위해서다.
조인, 조건, 정렬이 들어간 긴 SELECT문은 한 번 쓸 때도 번거롭고, 나중에 다시 보면 헷갈리기 쉽다.
이럴 때 그 조회 결과를 뷰로 만들어 두면, 이후에는 긴 SQL을 다시 쓰지 않고 뷰 이름만 조회하면 된다.


둘째, 필요한 정보만 보여주기 위해서다.
원본 테이블의 모든 열을 그대로 보여주지 않고, 꼭 필요한 열만 골라서 보이게 할 수 있다.
그래서 사용자에게 필요한 정보만 제한해서 보여주는 구조를 만들 때 유용하다.


핵심 특징

1. 테이블 대신 뷰 이름으로 조회할 수 있다

뷰를 한 번 만들어 두면 이후에는 일반 테이블을 조회하듯 사용할 수 있다.
그래서 복잡한 원본 구조를 몰라도 필요한 결과를 쉽게 확인할 수 있다.


2. 긴 SQL을 짧게 바꿔 준다

여러 테이블을 조인하고 조건을 붙여야 하는 조회문도,
뷰로 만들어 두면 다음부터는 짧은 형태로 다시 사용할 수 있다.


3. 필요한 열만 따로 보여줄 수 있다

원본 테이블에는 정보가 많이 들어 있어도,
뷰에는 필요한 열만 골라 담을 수 있다.
그래서 꼭 필요한 정보만 보여주는 데 적합하다.


4. 데이터베이스 안에 만들어 두는 객체다

뷰는 잠깐 쓰고 끝나는 문장이 아니라,
이름을 붙여 만들어 두고 계속 사용할 수 있는 데이터베이스 객체다.
그래서 생성하고, 필요 없으면 삭제하면서 관리한다.



이해 흐름

뷰는 아래 순서로 이해하면 쉽다.

1. 먼저 원본 테이블이 있다.
2. 그중에서 자주 보는 결과를 SELECT문으로 만든다.
3. 그 조회 결과에 이름을 붙인다.
4. 이후에는 긴 SQL 대신 그 이름을 조회해서 사용한다.

이 흐름으로 보면, 뷰는 자주 쓰는 조회 결과를 다시 쓰기 쉽게 정리해 둔 객체라고 이해할 수 있다.



코드 예제

예제: 직원 이름과 부서명을 쉽게 조회하는 뷰 만들기

CREATE VIEW v_emp_dept AS
SELECT e.ename, d.dname
FROM emp e
JOIN dept d
ON e.deptno = d.deptno;

SELECT * FROM v_emp_dept;

-- 출력결과 예시
-- ename   dname
-- SMITH   RESEARCH
-- ALLEN   SALES
-- WARD    SALES

이 코드는 직원 이름과 부서명을 매번 직접 조인해서 조회하지 않도록,
자주 쓰는 결과를 v_emp_dept라는 이름의 뷰로 만든 예제다.

핵심은 CREATE VIEW 뒤에 뷰 이름을 쓰고,
그 뒤에 저장해 둘 조회문을 붙인다는 점이다.

이렇게 한 번 만들어 두면 이후에는 다음처럼 더 짧게 사용할 수 있다.

SELECT * FROM v_emp_dept
WHERE dname = 'SALES';

-- 출력결과 예시
-- ename   dname
-- ALLEN   SALES
-- WARD    SALES

원래라면 emp와 dept를 다시 조인해야 하지만,
뷰를 만들고 나면 그 과정을 반복하지 않아도 된다.
이 점이 뷰의 가장 큰 장점이다.



헷갈리기 쉬운 부분

1. 뷰는 테이블처럼 보이지만, 테이블 자체와 똑같다고 생각하면 헷갈린다

조회할 때는 테이블처럼 사용할 수 있다.
하지만 처음 배울 때는 원본 테이블을 대신해서 결과를 보여 주는 조회용 객체라고 이해하는 편이 가장 쉽다.


2. 새로운 데이터를 따로 저장하는 테이블이라고 생각하면 헷갈리기 쉽다

뷰를 보면 새로운 테이블이 하나 더 생긴 것처럼 느껴질 수 있다.
하지만 초보자 기준에서는, 데이터를 새로 저장하는 용도라기보다 자주 쓰는 조회문을 편하게 다시 사용하기 위한 객체라고 이해하는 편이 쉽다.


3. 뷰의 핵심은 조회를 단순하게 만드는 데 있다

뷰는 단순히 모양만 바꾸는 기능이 아니다.
복잡한 SQL을 짧게 만들고, 필요한 정보만 보이게 해서 조회를 더 쉽게 만드는 데 의미가 있다.



한 줄로 잡기

뷰는 자주 사용하는 조회 결과를 이름 붙여 만들어 두고, 나중에 테이블처럼 다시 사용할 수 있게 한 조회용 객체다.

0개의 댓글