📋 학습 목차
SQL이란? 데이터베이스와 대화하는 언어
💡 핵심 한 줄 요약
SQL(Structured Query Language)은 데이터베이스에서 데이터를 조회·삽입·수정·삭제하기 위해 사용하는 표준 언어입니다. 영어 문장처럼 읽히는 직관적인 구문이 특징입니다.
🤔 왜 SQL을 배워야 할까요?
🏆 세계 표준 언어
MySQL, PostgreSQL, Oracle, SQLite 등 모든 관계형 DB에서 공통으로 사용. 한 번 배우면 어디서든 사용 가능
💼 현업 필수 스킬
백엔드 개발자, 데이터 분석가, DBA 등 IT 직군 대부분에서 SQL 능력 필수. 채용 공고의 70% 이상 요구
📈 데이터 기반 의사결정
비즈니스 데이터 분석, 리포트 작성, 매출 집계 등 업무에서 SQL 없이는 불가능한 작업이 많음
⚡ 쉽고 강력함
SELECT * FROM users WHERE age > 20 처럼 영어 문장과 유사하여 비전공자도 빠르게 익힐 수 있음
📊 SQL 명령어의 4가지 분류 (DML/DDL/DCL/TCL)
| 분류 | 영문 Full Name | 역할 | 주요 명령어 |
|---|---|---|---|
| DML | Data Manipulation Language | 데이터 조작 (조회/삽입/수정/삭제) | SELECT INSERT UPDATE DELETE |
| DDL | Data Definition Language | 구조 정의 (테이블 생성/수정/삭제) | CREATE ALTER DROP TRUNCATE |
| DCL | Data Control Language | 권한 제어 (접근 권한 부여/회수) | GRANT REVOKE |
| TCL | Transaction Control Language | 트랜잭션 제어 (커밋/롤백) | COMMIT ROLLBACK SAVEPOINT |
💡 이 가이드에서 집중할 내용: DML의 SELECT, INSERT, UPDATE, DELETE + DDL의 CREATE, ALTER, DROP을 완전히 마스터합니다!
SQL이란? — 데이터베이스와 대화하는 언어
💡 핵심 한 줄 요약
SQL(Structured Query Language)은 관계형 데이터베이스에 데이터를 저장·조회·수정·삭제하기 위해 사용하는 표준 언어입니다. "데이터베이스에게 한국어로 말 거는 것처럼" 명령하는 언어입니다!
😓 SQL 없이 데이터 찾기
- 수백만 줄 파일을 처음부터 끝까지 읽기
- 조건에 맞는 데이터를 일일이 비교
- 원하는 데이터 찾는 데 수분~수시간
- 동시에 여러 명이 작업하면 충돌 발생
😊 SQL로 데이터 찾기
- 한 줄 명령으로 수백만 건 즉시 검색
- 복잡한 조건도 자연어처럼 표현 가능
- 0.001초 이내에 원하는 결과 반환
- 수천 명 동시 접근해도 안전하게 처리
📊 SQL 명령어 4가지 분류 (DML / DDL / DCL / TCL)
| 분류 | 풀네임 | 역할 | 주요 명령어 |
|---|---|---|---|
| DML | Data Manipulation Language | 데이터 조작 (일상적으로 가장 많이 사용) | SELECTINSERTUPDATEDELETE |
| DDL | Data Definition Language | 테이블 구조 정의 (설계도 작성) | CREATEALTERDROPTRUNCATE |
| DCL | Data Control Language | 접근 권한 제어 (보안 관리) | GRANTREVOKE |
| TCL | Transaction Control Language | 트랜잭션 제어 (작업 확정/취소) | COMMITROLLBACK |
⚠️ SQL vs NoSQL 오해 바로잡기
SQL은 "언어"이고, MySQL·PostgreSQL은 "프로그램"입니다. SQL이라는 언어를 사용해서 MySQL/PostgreSQL/Oracle 등의 DBMS를 조작하는 것입니다. NoSQL은 SQL을 사용하지 않는 DB 방식의 총칭입니다.
SELECT - 데이터 조회 완전 마스터
💡 핵심 한 줄 요약
SELECT는 SQL에서 가장 많이 사용하는 명령어로, 데이터를 읽어오는(조회하는) 역할을 합니다. 현업에서 SQL 작업의 80% 이상이 SELECT입니다.
🏫 실습용 예시 테이블: students (학생 테이블)
| id | name | grade | score | subject | city |
|---|---|---|---|---|---|
| 1 | 홍길동 | 3학년 | 92 | 수학 | 서울 |
| 2 | 김영희 | 2학년 | 85 | 영어 | 부산 |
| 3 | 이철수 | 1학년 | 78 | 수학 | 서울 |
| 4 | 박지수 | 3학년 | 96 | 국어 | 대구 |
| 5 | 최민준 | 2학년 | 71 | 영어 | 부산 |
| 6 | 정미나 | 1학년 | 88 | 국어 | 서울 |
👆 이 테이블을 기준으로 아래 모든 SELECT 예제를 실습합니다.
📌 SELECT 기본 문법 구조
-- SELECT 기본 구조 (대괄호 안은 선택사항)
SELECT column1, column2, ... -- 조회할 열 (컬럼)
FROM table_name -- 조회할 테이블
[WHERE 조건] -- 필터링 조건 (선택)
[ORDER BY column ASC|DESC] -- 정렬 (선택)
[LIMIT n] -- 가져올 행 수 제한 (선택)
| 예제 | SQL 코드 | 결과 설명 |
|---|---|---|
| 모든 컬럼 조회 | SELECT * FROM students; | 전체 6행 모든 컬럼 반환 |
| 특정 컬럼만 조회 | SELECT name, score FROM students; | 이름과 점수 2개 컬럼만 반환 |
| 컬럼에 별칭 붙이기 (AS) | SELECT name AS 이름, score AS 점수 FROM students; | 결과 헤더를 '이름', '점수'로 표시 |
| 중복 제거 조회 (DISTINCT) | SELECT DISTINCT city FROM students; | 서울/부산/대구 3개 고유값만 반환 |
| 계산식 사용 | SELECT name, score * 1.1 AS 보정점수 FROM students; | 점수에 10% 가산하여 보정점수 컬럼으로 표시 |
⚠️ 현업에서 SELECT * 사용 시 주의!
SELECT * 는 공부할 때는 편리하지만, 현업에서는 필요한 컬럼만 명시하는 것이 원칙입니다. 불필요한 데이터 전송으로 네트워크 부하가 증가하고, 코드 가독성이 떨어지며, 스키마 변경 시 예기치 않은 오류가 발생할 수 있습니다.
SELECT — 데이터 조회 완전 마스터
💡 SELECT란?
SELECT는 SQL의 꽃! 데이터베이스에서 원하는 데이터를 읽어오는 명령어입니다. 현업에서 SQL의 80%는 SELECT입니다.
📋 실습에 사용할 샘플 테이블
이번 가이드 전체에서 이 세 가지 테이블을 사용합니다. 먼저 눈에 익혀두세요!
👤 users 테이블 (회원 정보)
| id | name | age | grade | created_at | |
|---|---|---|---|---|---|
| 1 | 홍길동 | hong@test.com | 28 | VIP | 2024-01-15 |
| 2 | 김영희 | kim@test.com | 34 | 일반 | 2024-02-20 |
| 3 | 이철수 | lee@test.com | 25 | 골드 | 2024-03-10 |
| 4 | 박민수 | park@test.com | 42 | VIP | 2024-04-05 |
| 5 | 최지현 | choi@test.com | 19 | 일반 | 2024-05-22 |
🛒 orders 테이블 (주문 정보)
| order_id | user_id | product_name | amount | status | order_date |
|---|---|---|---|---|---|
| 1001 | 1 | 노트북 | 1500000 | 완료 | 2024-06-01 |
| 1002 | 2 | 마우스 | 35000 | 완료 | 2024-06-03 |
| 1003 | 1 | 키보드 | 85000 | 배송중 | 2024-06-10 |
| 1004 | 3 | 모니터 | 320000 | 완료 | 2024-06-15 |
| 1005 | 4 | 웹캠 | 72000 | 취소 | 2024-06-20 |
🔍 SELECT 기본 문법 완전 해부
SQL SYNTAX — SELECT 기본 구조
SELECT 컬럼1, 컬럼2, ... -- 가져올 컬럼 지정 (* = 전체)
FROM 테이블명 -- 어느 테이블에서
WHERE 조건 -- 조건 필터링 (없으면 전체)
ORDER BY 컬럼명 ASC|DESC -- 정렬 방식
LIMIT 숫자 -- 가져올 행 수 제한
📌 SELECT 실전 예제 모음
WHERE - 조건으로 데이터 필터링
💡 핵심 한 줄 요약
WHERE는 조건을 지정해서 원하는 데이터만 골라내는 절입니다. SQL에서 WHERE를 잘 쓸수록 빠르고 정확한 쿼리를 작성할 수 있습니다.
📌 비교 연산자 완전 정리
| 연산자 | 의미 | SQL 예제 | 결과 |
|---|---|---|---|
| = | 같다 | WHERE city = '서울' | 서울에 사는 학생만 |
| <> 또는 != | 같지 않다 | WHERE subject <> '수학' | 수학 과목 제외한 학생 |
| > | 크다 | WHERE score > 85 | 85점 초과 학생 (홍길동, 박지수, 정미나) |
| >= | 크거나 같다 | WHERE score >= 85 | 85점 이상 학생 (+ 김영희 포함) |
| BETWEEN | 범위 조건 | WHERE score BETWEEN 80 AND 90 | 80~90점 구간 (80, 90 포함) |
| IN | 목록 중 하나 | WHERE city IN ('서울', '부산') | 서울 또는 부산 학생 |
| NOT IN | 목록 제외 | WHERE city NOT IN ('서울') | 서울 제외 학생 |
| LIKE | 패턴 검색 | WHERE name LIKE '김%' | '김'으로 시작하는 이름 (김영희) |
| IS NULL | NULL 여부 검사 | WHERE email IS NULL | 이메일이 없는 행 |
🔗 논리 연산자 AND, OR, NOT
-- AND: 두 조건 모두 만족
SELECT * FROM students
WHERE score >= 85 AND city = '서울';
-- 결과: 홍길동(92점, 서울), 정미나(88점, 서울)
-- OR: 두 조건 중 하나만 만족
SELECT * FROM students
WHERE city = '서울' OR score >= 90;
-- 결과: 서울 학생 + 90점 이상 학생
-- NOT: 조건 부정
SELECT * FROM students WHERE NOT subject = '수학';
-- 결과: 수학 과목이 아닌 학생들
🎯 LIKE 와일드카드 완전 정리
| 와일드카드 | 의미 | 예제 | 매칭되는 예시 |
|---|---|---|---|
| % | 0개 이상의 아무 문자 | LIKE '김%' | 김영희, 김철수, 김a, 김 |
| % | 끝에 특정 문자 | LIKE '%희' | 김영희, 민희, 희 |
| % | 중간에 특정 문자 포함 | LIKE '%영%' | 김영희, 영민, 이영수 |
| _ | 정확히 1개의 아무 문자 | LIKE '김__' | 김영희 (3글자 이름), 김철수 |
ORDER BY & LIMIT - 정렬과 결과 제한
📶 ORDER BY 정렬
-- 점수 오름차순 (낮은 점수부터)
SELECT name, score
FROM students
ORDER BY score ASC;
-- 점수 내림차순 (높은 점수부터)
SELECT name, score
FROM students
ORDER BY score DESC;
📏 LIMIT 결과 제한
-- 상위 3명만 조회 (TOP 3)
SELECT name, score
FROM students
ORDER BY score DESC
LIMIT 3;
-- 페이지네이션 (4번째부터 3개)
SELECT name, score
FROM students
LIMIT 3 OFFSET 3;
📌 복합 정렬 예제 (다중 컬럼 정렬)
-- 도시별 오름차순, 같은 도시면 점수 내림차순
SELECT name, city, score FROM students ORDER BY city ASC, score DESC;
WHERE — 조건으로 데이터 필터링
💡 WHERE란?
WHERE는 "조건에 맞는 행(Row)만 가져오세요"라는 필터입니다. 수백만 건 데이터 중 내가 원하는 데이터만 정확하게 뽑아낼 수 있습니다.
📌 WHERE 조건 연산자 완전 정리
| 연산자 | 의미 | 예시 | 결과 |
|---|---|---|---|
| = | 같다 | WHERE grade = 'VIP' | 등급이 VIP인 회원 |
| != 또는 <> | 같지 않다 | WHERE grade != 'VIP' | VIP가 아닌 회원 |
| > < >= <= | 크다/작다/이상/이하 | WHERE age >= 30 | 나이가 30 이상인 회원 |
| BETWEEN A AND B | A와 B 사이 (포함) | WHERE age BETWEEN 20 AND 30 | 20세 이상 30세 이하 |
| IN (값1, 값2, ...) | 목록 중 하나와 일치 | WHERE grade IN ('VIP','골드') | VIP 또는 골드 회원 |
| NOT IN | 목록 중 어느 것도 아닌 | WHERE grade NOT IN ('VIP') | VIP가 아닌 모든 회원 |
| LIKE '패턴' | 패턴 일치 검색 | WHERE email LIKE '%@gmail%' | gmail 포함 이메일 |
| IS NULL | NULL인 데이터 | WHERE phone IS NULL | 전화번호 없는 회원 |
| IS NOT NULL | NULL이 아닌 데이터 | WHERE phone IS NOT NULL | 전화번호 있는 회원 |
| AND | 두 조건 모두 참 | WHERE age >= 30 AND grade='VIP' | 30세 이상이면서 VIP |
| OR | 둘 중 하나라도 참 | WHERE grade='VIP' OR grade='골드' | VIP이거나 골드인 회원 |
📌 LIKE 패턴 와일드카드 상세
| 패턴 | 의미 | 예시 | 매칭 예 |
|---|---|---|---|
| % | 0개 이상 임의 문자 | LIKE '김%' | 김, 김영희, 김철수, 김민준... |
| % | 끝에 '~'으로 끝나는 | LIKE '%수' | 철수, 영수, 민수... |
| %..% | 중간에 포함 | LIKE '%test%' | test포함 모든 이메일 |
| _ | 정확히 1개 문자 | LIKE '김_수' | 김철수, 김민수 (3글자만) |
📌 WHERE 복합 조건 실전 예제
예제: 30세 이상이면서 VIP 등급인 회원의 이름과 이메일 조회
SELECT name, email, age, grade
FROM users
WHERE age >= 30
AND grade = 'VIP';
-- 결과: 박민수 (42세, VIP) 1건 반환
예제: '김' 또는 '이'씨 성을 가진 회원 조회
SELECT name, email
FROM users
WHERE name LIKE '김%'
OR name LIKE '이%';
-- 결과: 김영희, 이철수 2건 반환
예제: 주문금액이 50,000원 이상 500,000원 이하이고 완료 상태인 주문
SELECT order_id, product_name, amount, status
FROM orders
WHERE amount BETWEEN 50000 AND 500000
AND status = '완료';
-- 결과: 마우스(35000 제외), 키보드(배송중 제외), 모니터(320000 완료) → 모니터 1건
⚠️ 현업 주의사항 — AND와 OR 우선순위
-- ❌ 의도와 다른 결과 (AND가 OR보다 먼저 실행됨!)
WHERE age >= 30 OR grade = 'VIP' AND status = '완료'
-- ✅ 괄호로 명확하게 우선순위 지정
WHERE (age >= 30 OR grade = 'VIP') AND status = '완료'
AND는 OR보다 연산 우선순위가 높습니다. 복합 조건 시 반드시 괄호()로 명확히 구분하세요!
INSERT INTO - 데이터 삽입 완전 정복
💡 핵심 한 줄 요약
INSERT INTO는 테이블에 새로운 데이터(행)를 추가하는 명령어입니다. 회원가입, 주문 접수, 게시글 작성 등 모든 '데이터 입력' 상황에 사용됩니다.
📌 INSERT 기본 문법과 다양한 사용법
-- 방법 1: 컬럼명 명시 (권장 방법)
INSERT INTO students (name, grade, score, subject, city)
VALUES ('강민서', '2학년', 90, '수학', '인천');
-- 방법 2: 컬럼 순서대로 전부 입력 (컬럼명 생략)
INSERT INTO students
VALUES (7, '강민서', '2학년', 90, '수학', '인천');
-- 방법 3: 여러 행 한번에 삽입 (다중 INSERT, 성능 좋음)
INSERT INTO students (name, grade, score, subject, city)
VALUES
('강민서', '2학년', 90, '수학', '인천'),
('오지훈', '3학년', 83, '영어', '광주'),
('서예린', '1학년', 95, '국어', '서울');
✅ INSERT 올바른 습관
- 컬럼명을 항상 명시할 것
- 여러 행 삽입 시 다중 INSERT 사용
- AUTO_INCREMENT ID는 생략 가능
- DEFAULT 값 있는 컬럼 생략 가능
❌ INSERT 주의사항
- NOT NULL 컬럼은 반드시 값 제공
- PK 중복 시 오류 발생
- UNIQUE 제약 위반 시 오류
- 데이터 타입 불일치 주의
UPDATE SET - 데이터 수정 완전 정복
⚠️ 절대 절대 잊지 마세요!
UPDATE는 반드시 WHERE 조건을 함께 사용해야 합니다. WHERE 없이 UPDATE하면 테이블의 모든 행이 수정되는 대참사가 발생합니다!
📌 UPDATE 문법과 실전 예제
-- 기본 구조
UPDATE 테이블명
SET 컬럼1 = 값1, 컬럼2 = 값2
WHERE 조건; -- ← 필수!! 없으면 전체 수정!!
-- 예제 1: 특정 학생의 점수 수정
UPDATE students
SET score = 95
WHERE id = 3; -- id가 3인 이철수의 점수만 수정
-- 예제 2: 여러 컬럼 동시 수정
UPDATE students
SET score = 80, city = '대전'
WHERE name = '최민준';
-- 예제 3: 조건부 일괄 수정 (점수 10점 가산)
UPDATE students
SET score = score + 10
WHERE subject = '영어'; -- 영어 수강생 전체 10점 가산
🚨 실제 현업에서 발생한 사고 사례
-- ❌ WHERE를 빠뜨린 대참사
UPDATE users SET password = 'new_password'; -- 모든 사용자 비밀번호가 동일하게 변경!!
💡 해결책: UPDATE 전 반드시 SELECT로 먼저 대상을 확인하고, 트랜잭션(BEGIN; ... COMMIT;)과 함께 사용하는 습관을 들이세요!
DELETE FROM - 데이터 삭제 완전 정복
🚨 DELETE는 되돌릴 수 없습니다!
DELETE도 UPDATE와 마찬가지로 WHERE 조건 없이 실행하면 테이블의 모든 데이터가 삭제됩니다. 반드시 WHERE를 명시하고, 중요한 삭제는 트랜잭션으로 감싸세요.
📌 DELETE 문법과 실전 예제
-- 기본 구조
DELETE FROM 테이블명
WHERE 조건; -- ← 필수!! 없으면 전체 삭제!!
-- 예제 1: 특정 학생 삭제
DELETE FROM students
WHERE id = 5; -- id가 5인 최민준만 삭제
-- 예제 2: 조건부 삭제 (60점 미만 학생 삭제)
DELETE FROM students
WHERE score < 60;
-- 안전한 삭제 패턴 (트랜잭션 사용)
BEGIN; -- 트랜잭션 시작
SELECT * FROM students WHERE id = 5; -- 먼저 확인
DELETE FROM students WHERE id = 5; -- 삭제
COMMIT; -- 확인 후 확정 (문제 시 ROLLBACK;)
⚖️ DELETE vs TRUNCATE vs DROP 비교
| 명령어 | 삭제 대상 | 롤백 가능? | 사용 시나리오 |
|---|---|---|---|
| DELETE | 조건에 맞는 행(들) | ✅ 가능 | 특정 데이터 삭제, 조건부 삭제 |
| TRUNCATE | 테이블의 모든 데이터 | ❌ 불가 | 테이블 초기화 (구조는 유지) |
| DROP | 테이블 자체를 삭제 | ❌ 불가 | 테이블 구조까지 완전 제거 |
ORDER BY & LIMIT — 정렬과 제한
💡 ORDER BY란?
ORDER BY는 조회 결과를 특정 컬럼을 기준으로 오름차순(ASC) 또는 내림차순(DESC)으로 정렬합니다. LIMIT는 결과 수를 제한합니다. "가장 최근 주문 10개만 보여줘" 같은 요구에 필수입니다!
예제 1: 나이 오름차순 정렬 (어린 순)
SELECT name, age, grade
FROM users
ORDER BY age ASC; -- ASC = 오름차순 (기본값, 생략 가능)
-- 결과: 최지현(19), 이철수(25), 홍길동(28), 김영희(34), 박민수(42)
예제 2: 주문금액 내림차순 정렬 (비싼 순)
SELECT product_name, amount, status
FROM orders
ORDER BY amount DESC; -- DESC = 내림차순
-- 결과: 노트북(150만), 모니터(32만), 키보드(8.5만), 웹캠(7.2만), 마우스(3.5만)
예제 3: LIMIT으로 상위 3건만 조회 (Top 3)
SELECT product_name, amount
FROM orders
ORDER BY amount DESC
LIMIT 3; -- 상위 3건만!
-- 결과: 노트북(150만), 모니터(32만), 키보드(8.5만)
예제 4: LIMIT + OFFSET으로 페이징 처리 (현업 필수!)
-- 게시판 2페이지: 1페이지(1~10번)를 건너뛰고 11~20번 조회
SELECT *
FROM posts
ORDER BY created_at DESC
LIMIT 10 OFFSET 10; -- 10개씩, 10번 건너뛰기
-- 공식: OFFSET = (페이지번호 - 1) × 페이지당건수
-- 1페이지: LIMIT 10 OFFSET 0
-- 2페이지: LIMIT 10 OFFSET 10
-- 3페이지: LIMIT 10 OFFSET 20
예제 5: 다중 컬럼 정렬 (복합 정렬)
-- 등급 오름차순 → 같은 등급 내에서 나이 내림차순
SELECT name, age, grade
FROM users
ORDER BY grade ASC, age DESC;
-- 쉼표(,)로 여러 기준 지정 가능!
INSERT INTO — 데이터 삽입 완전 마스터
💡 INSERT INTO란?
INSERT INTO는 테이블에 새 행(Row)을 추가하는 명령어입니다. 회원가입, 글 작성, 주문 생성 등 모든 "데이터 생성" 작업에 사용됩니다.
📋 INSERT 문법 패턴 3가지
패턴 1: 기본형 — 컬럼 지정 후 값 삽입 (권장!)
INSERT INTO users (name, email, age, grade)
VALUES ('정다은', 'jung@test.com', 27, '일반');
-- 컬럼 순서를 명시하면 테이블 구조가 변경되어도 안전!
패턴 2: 다중 행 삽입 — 한 번에 여러 건 INSERT
INSERT INTO users (name, email, age, grade)
VALUES
('강민준', 'kang@test.com', 31, '골드'),
('윤서연', 'yoon@test.com', 26, '일반'),
('조현우', 'cho@test.com', 38, 'VIP');
-- 한 번의 쿼리로 3건 동시 삽입! 성능상 유리합니다.
패턴 3: INSERT ... SELECT — 다른 테이블 데이터로 삽입
-- VIP 회원을 별도 VIP 전용 테이블로 복사
INSERT INTO vip_users (name, email)
SELECT name, email
FROM users
WHERE grade = 'VIP';
-- SELECT 결과를 그대로 다른 테이블에 삽입!
⚠️ INSERT 주의사항 (현업 실수 TOP 3)
| 실수 유형 | 잘못된 코드 | 올바른 코드 |
|---|---|---|
| 중복 이메일 삽입 | VALUES ('hong@test.com') | INSERT IGNORE 또는 ON DUPLICATE KEY |
| 컬럼명 생략 | INSERT INTO users VALUES (...) | INSERT INTO users (col1,...) |
| NULL 허용 안되는 컬럼 | name 컬럼 누락 | NOT NULL 컬럼은 반드시 포함 |
MySQL 설치 및 실습 환경 구축
🛠 실습 환경 3가지 선택지
🐬
MySQL Workbench
PC에 직접 설치. 가장 실무에 가까운 환경
⭐ 추천🦆
DBeaver (무료)
다양한 DB 지원. 현업에서 많이 사용
현업 인기☁️
DB Fiddle (온라인)
설치 없이 브라우저에서 바로 실습
빠른 시작📋 MySQL + DBeaver 설치 단계 (Windows/Mac 공통)
| 단계 | 작업 | URL / 메모 |
|---|---|---|
| 1 | MySQL Community 다운로드 | dev.mysql.com/downloads → MySQL Installer 선택 |
| 2 | 설치 시 "Developer Default" 선택 | MySQL Server + Workbench 한 번에 설치됨 |
| 3 | root 비밀번호 설정 | 반드시 기억! 잊으면 재설치 필요 |
| 4 | DBeaver Community 다운로드 (선택) | dbeaver.io → Community Edition (무료) |
| 5 | 첫 데이터베이스 생성 | CREATE DATABASE mydb; USE mydb; |
🚀 첫 실습: 데이터베이스 생성부터 데이터 입력까지
-- 1단계: 데이터베이스 생성 및 선택
CREATE DATABASE school_db;
USE school_db;
-- 2단계: 테이블 생성
CREATE TABLE students (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
grade VARCHAR(10) NOT NULL,
score INT DEFAULT 0,
subject VARCHAR(20),
city VARCHAR(20),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 3단계: 데이터 삽입
INSERT INTO students (name, grade, score, subject, city) VALUES
('홍길동', '3학년', 92, '수학', '서울'),
('김영희', '2학년', 85, '영어', '부산'),
('이철수', '1학년', 78, '수학', '서울'),
('박지수', '3학년', 96, '국어', '대구');
-- 4단계: 결과 확인
SELECT * FROM students;
UPDATE SET — 데이터 수정 완전 마스터
💡 UPDATE란?
UPDATE는 이미 존재하는 데이터를 수정하는 명령어입니다. 반드시 WHERE와 함께 사용하세요! WHERE 없이 실행하면 테이블 전체가 수정되는 대참사가 발생합니다!
🚨 절대 주의! UPDATE는 WHERE 없이 실행 금지!
-- ❌ 절대 금지: WHERE 없는 UPDATE → 모든 회원 등급이 VIP가 됨!
UPDATE users SET grade = 'VIP';
-- ✅ 올바른 방법: WHERE로 대상 특정!
UPDATE users SET grade = 'VIP' WHERE id = 2;
📌 UPDATE 실전 예제 모음
예제 1: 단일 컬럼 수정 — 특정 회원 등급 변경
UPDATE users
SET grade = 'VIP'
WHERE id = 2;
-- id가 2인 김영희의 등급만 VIP로 변경
예제 2: 여러 컬럼 동시 수정
UPDATE users
SET
email = 'kim_new@test.com',
grade = '골드',
updated_at = NOW() -- NOW()는 현재 시각 자동 입력
WHERE id = 2;
예제 3: 계산식으로 수정 — 주문금액 10% 할인
UPDATE orders
SET amount = amount * 0.9 -- 기존값의 90% (10% 할인)
WHERE status = '배송중';
-- 배송중인 주문만 10% 할인 적용
예제 4: CASE WHEN으로 조건별 다른 값 설정 (현업 자주 사용!)
-- 나이에 따라 등급 자동 분류
UPDATE users
SET grade = CASE
WHEN age >= 40 THEN 'VIP'
WHEN age >= 30 THEN '골드'
ELSE '일반'
END;
-- IF-ELSE처럼 조건별로 다른 값 설정 가능!
DELETE FROM — 데이터 삭제 완전 마스터
💡 DELETE란?
DELETE는 테이블에서 행(Row)을 삭제하는 명령어입니다. UPDATE와 마찬가지로 반드시 WHERE와 함께! 삭제된 데이터는 ROLLBACK 없이는 복구 불가능합니다.
📊 DELETE vs TRUNCATE vs DROP 비교
| 명령어 | 삭제 범위 | WHERE 사용 | ROLLBACK | 테이블 구조 | 속도 |
|---|---|---|---|---|---|
| DELETE | 조건에 맞는 행만 | ✅ 가능 | ✅ 가능 | 유지됨 | 느림 |
| TRUNCATE | 전체 행 | ❌ 불가 | ❌ 불가 | 유지됨 (초기화) | 빠름 |
| DROP | 테이블 자체 삭제 | ❌ 불가 | ❌ 불가 | 삭제됨 | 빠름 |
예제 1: 특정 주문 삭제
DELETE FROM orders
WHERE order_id = 1005;
-- 취소된 주문(order_id=1005) 삭제
예제 2: 조건 삭제 — 취소 상태 주문 전체 삭제
DELETE FROM orders
WHERE status = '취소';
-- 현업에서는 실제 삭제보다 status = '취소'로 소프트 삭제를 선호!
예제 3: 현업 패턴 — 소프트 삭제 (Soft Delete)
-- 실제 삭제 대신 is_deleted 플래그만 변경 (복구 가능!)
UPDATE users
SET
is_deleted = 1,
deleted_at = NOW()
WHERE id = 3;
-- 조회 시 삭제된 데이터 제외
SELECT * FROM users WHERE is_deleted = 0;
💼 현업 꿀팁 — Soft Delete가 표준인 이유
대부분의 서비스에서는 실제 DELETE 대신 is_deleted = 1 또는 deleted_at 타임스탬프를 통한 소프트 삭제를 사용합니다. 이유는: ① 데이터 복구 가능 ② 통계/분석에 활용 ③ 규정 준수(개인정보 보관 의무). 실제 DELETE는 로그/임시 데이터 정리 등에만 사용합니다.
DDL - 테이블 생성, 수정, 삭제 완전 정복
📌 CREATE TABLE - 테이블 구조 설계
-- 현업 수준의 사용자 테이블 설계 예시
CREATE TABLE users (
user_id INT AUTO_INCREMENT, -- 자동 증가 정수 ID
username VARCHAR(50) NOT NULL UNIQUE, -- 중복 불가, 필수
email VARCHAR(100) NOT NULL UNIQUE, -- 이메일 중복 불가
password VARCHAR(255) NOT NULL, -- 해시값 저장 (보안)
age INT CHECK (age >= 0 AND age <= 150),
status ENUM('active','inactive','banned') DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (user_id)
);
🔧 ALTER TABLE - 기존 테이블 구조 변경
-- 컬럼 추가
ALTER TABLE students ADD COLUMN phone VARCHAR(20);
-- 컬럼 타입 변경
ALTER TABLE students MODIFY COLUMN score DECIMAL(5,2);
-- 컬럼 이름 변경 (MySQL 8.0+)
ALTER TABLE students RENAME COLUMN grade TO school_year;
-- 컬럼 삭제
ALTER TABLE students DROP COLUMN phone;
📊 자주 쓰는 데이터 타입 + AUTO_INCREMENT 정리
| 컬럼 용도 | 권장 타입 | 예제 | 이유 |
|---|---|---|---|
| 기본키 ID | INT AUTO_INCREMENT | id INT AUTO_INCREMENT PK | 자동으로 1씩 증가 |
| 이름, 제목 | VARCHAR(50~255) | name VARCHAR(50) | 가변 길이, 공간 효율적 |
| 금액, 가격 | DECIMAL(10,2) | price DECIMAL(10,2) | 정확한 소수, FLOAT 금지! |
| 긴 텍스트 | TEXT | content TEXT | 게시글, 댓글 본문 |
| 상태값 | ENUM('a','b','c') | status ENUM('on','off') | 정해진 값만 허용, 공간 절약 |
| 생성/수정일시 | TIMESTAMP DEFAULT NOW() | created_at TIMESTAMP | 자동으로 현재 시간 저장 |
집계 함수와 GROUP BY - 데이터 요약
💡 핵심 한 줄 요약
집계 함수는 여러 행의 데이터를 하나의 결과값으로 계산합니다. GROUP BY와 함께 사용하면 강력한 데이터 분석이 가능합니다.
📊 핵심 집계 함수 5가지
| 함수 | 역할 | SQL 예제 | 결과 |
|---|---|---|---|
| COUNT(*) | 전체 행 수 세기 | SELECT COUNT(*) FROM students; | 6 (전체 학생 수) |
| SUM(col) | 합계 계산 | SELECT SUM(score) FROM students; | 510 (전체 점수 합) |
| AVG(col) | 평균 계산 | SELECT AVG(score) FROM students; | 85 (평균 점수) |
| MAX(col) | 최댓값 | SELECT MAX(score) FROM students; | 96 (최고 점수) |
| MIN(col) | 최솟값 | SELECT MIN(score) FROM students; | 71 (최저 점수) |
-- GROUP BY: 그룹별로 집계
-- 과목별 평균 점수와 학생 수 조회
SELECT
subject AS 과목,
COUNT(*) AS 학생수,
ROUND(AVG(score), 1) AS 평균점수,
MAX(score) AS 최고점,
MIN(score) AS 최저점
FROM students
GROUP BY subject
ORDER BY 평균점수 DESC;
-- HAVING: GROUP BY 결과에 조건 추가 (WHERE와 차이!)
-- 평균 점수 85점 이상인 과목만 조회
SELECT subject, AVG(score) AS 평균점수
FROM students
GROUP BY subject
HAVING AVG(score) >= 85; -- WHERE가 아닌 HAVING 사용!
📌 WHERE vs HAVING 핵심 차이
| 구분 | WHERE | HAVING |
|---|---|---|
| 적용 시점 | GROUP BY 이전 (개별 행 필터) | GROUP BY 이후 (그룹 필터) |
| 집계함수 사용 | ❌ 불가 | ✅ 가능 |
| 예시 | WHERE score >= 80 | HAVING AVG(score) >= 80 |
MySQL 설치 및 실습 환경 구축
🖥️ 실습 환경 구성 (Windows / Mac 공통)
MySQL
관계형 DB 엔진 (무료)
필수 설치DBeaver
GUI 관리 도구 (무료)
권장 설치VS Code
SQL 파일 편집 (무료)
선택 설치📋 실습용 데이터베이스 + 테이블 생성 SQL (복사해서 바로 실행!)
STEP 1 — 데이터베이스 생성 및 선택
-- 실습용 데이터베이스 생성
CREATE DATABASE practice_db
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci; -- 한글 지원!
-- 생성한 데이터베이스 선택
USE practice_db;
STEP 2 — users 테이블 생성
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY, -- 자동증가 기본키
name VARCHAR(50) NOT NULL, -- 이름 필수
email VARCHAR(100) NOT NULL UNIQUE, -- 이메일 중복불가
age INT CHECK (age >= 0 AND age <= 150), -- 나이 범위 제한
grade VARCHAR(20) DEFAULT '일반', -- 기본 등급
is_deleted TINYINT(1) DEFAULT 0, -- 소프트 삭제용
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- 생성 시각 자동
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP -- 수정 시각 자동
);
STEP 3 — orders 테이블 생성 (외래키 포함)
CREATE TABLE orders (
order_id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
product_name VARCHAR(200) NOT NULL,
amount DECIMAL(12, 0) NOT NULL, -- 금액은 DECIMAL 필수!
status VARCHAR(20) DEFAULT '대기',
order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) -- FK 설정!
ON DELETE RESTRICT -- 회원 삭제 시 주문 있으면 거부
ON UPDATE CASCADE -- 회원 ID 변경 시 자동 반영
);
STEP 4 — 샘플 데이터 삽입
INSERT INTO users (name, email, age, grade) VALUES
('홍길동', 'hong@test.com', 28, 'VIP'),
('김영희', 'kim@test.com', 34, '일반'),
('이철수', 'lee@test.com', 25, '골드'),
('박민수', 'park@test.com', 42, 'VIP'),
('최지현', 'choi@test.com', 19, '일반');
INSERT INTO orders (user_id, product_name, amount, status) VALUES
(1, '노트북', 1500000, '완료'),
(2, '마우스', 35000, '완료'),
(1, '키보드', 85000, '배송중'),
(3, '모니터', 320000, '완료'),
(4, '웹캠', 72000, '취소');
실습 프로젝트: 학생 성적 관리 시스템
🎯 프로젝트 목표
이번에 배운 모든 SQL을 종합하여 실제로 동작하는 학생 성적 관리 시스템을 처음부터 만들어봅니다. 이 실습을 완료하면 SQL 기초를 완전히 체득할 수 있습니다.
📐 시스템 구조 (3개 테이블)
📋 students (학생)
student_id (PK)
name
grade
city
created_at
📚 subjects (과목)
subject_id (PK)
subject_name
teacher
📊 scores (성적)
score_id (PK)
student_id (FK)
subject_id (FK)
score
exam_date
-- ① 데이터베이스 생성
CREATE DATABASE grade_management;
USE grade_management;
-- ② students 테이블 생성
CREATE TABLE students (
student_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
grade VARCHAR(10) NOT NULL,
city VARCHAR(20),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- ③ subjects 테이블 생성
CREATE TABLE subjects (
subject_id INT AUTO_INCREMENT PRIMARY KEY,
subject_name VARCHAR(30) NOT NULL UNIQUE,
teacher VARCHAR(50)
);
-- ④ scores 테이블 생성 (외래키 포함)
CREATE TABLE scores (
score_id INT AUTO_INCREMENT PRIMARY KEY,
student_id INT NOT NULL,
subject_id INT NOT NULL,
score INT CHECK (score >= 0 AND score <= 100),
exam_date DATE NOT NULL,
FOREIGN KEY (student_id) REFERENCES students(student_id),
FOREIGN KEY (subject_id) REFERENCES subjects(subject_id)
);
-- ⑤ 샘플 데이터 삽입
INSERT INTO students (name, grade, city) VALUES
('홍길동', '3학년', '서울'), ('김영희', '2학년', '부산'),
('이철수', '1학년', '서울'), ('박지수', '3학년', '대구');
INSERT INTO subjects (subject_name, teacher) VALUES
('수학', '김선생'), ('영어', '이선생'), ('국어', '박선생');
INSERT INTO scores (student_id, subject_id, score, exam_date) VALUES
(1, 1, 92, '2024-03-15'), (1, 2, 78, '2024-03-15'),
(2, 2, 85, '2024-03-15'), (2, 3, 90, '2024-03-15'),
(3, 1, 78, '2024-03-15'), (4, 3, 96, '2024-03-15');
-- ⑥ 학생별 평균 점수 조회 (GROUP BY 활용)
SELECT s.name AS 학생이름, ROUND(AVG(sc.score),1) AS 평균점수,
COUNT(sc.score_id) AS 시험횟수, MAX(sc.score) AS 최고점
FROM students s
JOIN scores sc ON s.student_id = sc.student_id
GROUP BY s.student_id, s.name
ORDER BY 평균점수 DESC;
현업 면접 SQL Q&A + 학습 로드맵
💼 현업 실무 면접 단골 SQL 질문 TOP 8
Q1. DELETE, TRUNCATE, DROP의 차이를 설명하세요.
A: DELETE는 WHERE 조건으로 특정 행을 삭제하며 롤백 가능합니다. TRUNCATE는 테이블 전체 데이터를 빠르게 삭제하지만 롤백이 불가능하고 테이블 구조는 남습니다. DROP은 테이블 자체를 완전히 삭제하며 복구 불가능합니다. 현업에서는 안전을 위해 삭제 전 반드시 SELECT로 대상을 확인하고 트랜잭션을 사용합니다.
Q2. WHERE와 HAVING의 차이를 설명하세요.
A: WHERE는 GROUP BY 이전에 개별 행에 조건을 적용하며 집계 함수를 사용할 수 없습니다. HAVING은 GROUP BY 이후 그룹화된 결과에 조건을 적용하며 AVG(), COUNT() 같은 집계 함수 사용이 가능합니다. "평균 점수가 80점 이상인 과목만"과 같은 조건은 반드시 HAVING을 사용해야 합니다.
Q3. NULL과 빈 문자열("")의 차이는 무엇인가요?
A: NULL은 값이 존재하지 않는 상태(알 수 없음)이고, 빈 문자열은 길이가 0인 문자열 값입니다. NULL은 비교 연산자(=, !=)로 검사 불가능하며 반드시 IS NULL / IS NOT NULL을 사용해야 합니다. 집계 함수에서 COUNT(*)는 NULL 포함 전체 행을 세지만, COUNT(col)은 NULL을 제외하고 셉니다.
Q4. DISTINCT와 GROUP BY의 차이는?
A: DISTINCT는 중복된 행을 제거하여 고유한 값만 반환합니다. GROUP BY는 그룹화 후 집계 함수와 함께 사용하여 통계를 낼 수 있습니다. 단순 중복 제거에는 DISTINCT, 집계 분석에는 GROUP BY를 사용합니다. 대용량 데이터에서는 GROUP BY가 일반적으로 더 빠릅니다.
Q5. UPDATE나 DELETE 시 실수를 방지하는 방법은?
A: ① 먼저 동일한 WHERE 조건으로 SELECT를 실행하여 대상 확인 ② BEGIN(트랜잭션 시작) 후 UPDATE/DELETE 실행 ③ 결과를 확인 후 문제 없으면 COMMIT, 문제 있으면 ROLLBACK ④ 중요 작업 전 백업 수행. 현업에서 WHERE 없는 UPDATE/DELETE는 회사를 잠깐 뒤집어놓을 수 있는 실수입니다.
Q6. 현업에서 SELECT * 를 사용하면 안 되는 이유는?
A: ① 불필요한 컬럼까지 전송하여 네트워크 부하 증가 ② 인덱스를 활용한 커버링 인덱스(covering index) 최적화 불가 ③ 컬럼 추가/삭제 시 예기치 않은 버그 발생 가능 ④ 코드 가독성 저하. 현업에서는 항상 필요한 컬럼만 명시하는 것이 원칙입니다.
Q7. AUTO_INCREMENT로 생성된 ID가 1, 2, 3, 5, 6일 때 4는 왜 없을까요?
A: AUTO_INCREMENT는 한 번 증가하면 롤백되어도 되돌아가지 않습니다. 4번 행이 INSERT 시도 후 트랜잭션 롤백이나 에러로 취소되었을 가능성이 높습니다. 이는 정상적인 동작이며, ID 연속성이 보장되지 않는 것은 AUTO_INCREMENT의 설계 특성입니다. ID 순서에 비즈니스 로직을 의존해서는 안 됩니다.
Q8. SQL 쿼리의 실행 순서는 어떻게 되나요?
A: SQL은 작성 순서(SELECT-FROM-WHERE-GROUP BY-HAVING-ORDER BY-LIMIT)와 실제 실행 순서가 다릅니다. 실행 순서: FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT. 이를 이해하면 WHERE에서 집계 함수를 쓸 수 없는 이유, SELECT에서 만든 별칭(AS)을 WHERE에서 사용할 수 없는 이유를 이해할 수 있습니다.
🗺️ 데이터베이스 개발자 학습 로드맵
| 단계 | 학습 내용 | 기간 | 상태 |
|---|---|---|---|
| 1단계 | DB 개념 이해 - 테이블, 키, ACID, DBMS 비교 (Guide0001) | 1~2주 | ✅ 완료 |
| 2단계 | SQL 기초 - SELECT, WHERE, INSERT, UPDATE, DELETE, DDL (Guide0002) | 3~4주 | 📖 현재 |
| 3단계 | SQL 심화 - JOIN, GROUP BY, 서브쿼리, 인덱스 (Guide0003) | 2~3주 | ⏳ 예정 |
| 4단계 | DB 설계 - 정규화, ERD, 쇼핑몰 DB 설계 (Guide0004) | 2~3주 | ⏳ 예정 |
| 5단계 | NoSQL 입문 - MongoDB, Redis (Guide0005) | 2주 | ⏳ 예정 |
| 6단계 | 실전 활용 - 백엔드 연동(ORM), 트랜잭션, 보안 (Guide0006) | 2주 | ⏳ 예정 |
| 7단계 | 실전 프로젝트 - 블로그/쇼핑몰 DB 전체 설계 및 구현 (Guide0007) | 3~4주 | ⏳ 예정 |
🔧 필수 실습 도구
- MySQL 8.0+ - 관계형 DB 실습 (무료)
- DBeaver Community - GUI 관리 도구 (무료)
- DB Fiddle - 온라인 SQL 실습 (설치 불필요)
- SQLiteOnline.com - 간단한 실습용
📚 추천 학습 자료
- SQLZoo.net - 인터랙티브 SQL 학습
- LeetCode SQL - 실전 문제 풀이
- HackerRank SQL - 단계별 도전 문제
- W3Schools SQL - 레퍼런스 + 빠른 실습
🎉
수고하셨습니다!
SELECT부터 DDL, GROUP BY까지 SQL 기초를 완전 정복했습니다!
이 내용을 완전히 이해하고 직접 쿼리를 작성할 수 있다면 현업 DB 개발자로서 실력을 갖춘 것입니다.
다음 단계 →
DatabaseDevGuide0003
SQL 심화 - JOIN, 서브쿼리, 인덱스 완전 정복
DDL — 테이블 생성·수정·삭제 완전 마스터
💡 DDL(Data Definition Language)이란?
DDL은 데이터베이스 구조(스키마)를 정의하고 수정하는 명령어입니다. 집 짓기로 비유하면 설계도(테이블 구조)를 만들고 수정하는 작업입니다. DDL 명령은 자동 COMMIT됩니다 (롤백 불가!).
🔨 CREATE TABLE — 테이블 생성 상세
-- 가장 완전한 형태의 CREATE TABLE 예시
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(200) NOT NULL COMMENT '상품명',
price DECIMAL(12, 0) NOT NULL DEFAULT 0 COMMENT '판매가',
stock INT NOT NULL DEFAULT 0 COMMENT '재고수량',
category VARCHAR(50),
description TEXT,
is_active TINYINT(1) DEFAULT 1 COMMENT '판매 여부',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='상품 테이블';
✏️ ALTER TABLE — 테이블 구조 수정
-- 1. 컬럼 추가
ALTER TABLE users
ADD COLUMN phone VARCHAR(20) AFTER email; -- email 컬럼 뒤에 추가
-- 2. 컬럼 수정 (타입/이름 변경)
ALTER TABLE users
MODIFY COLUMN grade VARCHAR(30) DEFAULT '일반'; -- 길이 변경
-- 3. 컬럼 이름 변경
ALTER TABLE users
RENAME COLUMN grade TO membership_grade;
-- 4. 컬럼 삭제
ALTER TABLE users
DROP COLUMN phone;
-- 5. 테이블 이름 변경
RENAME TABLE users TO members;
-- 6. 인덱스 추가 (검색 성능 향상)
ALTER TABLE users
ADD INDEX idx_email (email);
⚠️ DROP TABLE 주의!
-- 테이블 완전 삭제 (복구 불가!)
DROP TABLE users;
-- 존재할 때만 삭제 (에러 방지)
DROP TABLE IF EXISTS users;
💡 SHOW 명령어 활용
-- DB 목록 조회
SHOW DATABASES;
-- 테이블 목록 조회
SHOW TABLES;
-- 테이블 구조 보기
DESCRIBE users;
집계 함수와 GROUP BY — 데이터 통계 분석
💡 집계 함수란?
여러 행의 데이터를 하나로 요약하는 함수입니다. "전체 주문 수", "평균 나이", "최대 금액" 같은 통계 분석에 필수입니다. GROUP BY와 함께 사용하면 그룹별 통계를 낼 수 있습니다.
📊 집계 함수 완전 정리
| 함수 | 기능 | 예시 | 결과 | NULL 처리 |
|---|---|---|---|---|
| COUNT(*) | 전체 행 수 | COUNT(*) | 5 (전체 회원 수) | NULL 포함 |
| COUNT(col) | NULL 제외한 행 수 | COUNT(phone) | 전화번호 있는 수 | NULL 제외 |
| SUM(col) | 합계 | SUM(amount) | 전체 주문금액 합계 | NULL 무시 |
| AVG(col) | 평균 | AVG(age) | 회원 평균 나이 | NULL 무시 |
| MAX(col) | 최댓값 | MAX(amount) | 최고 주문금액 | NULL 무시 |
| MIN(col) | 최솟값 | MIN(age) | 최연소 회원 나이 | NULL 무시 |
📌 GROUP BY + HAVING 실전 예제
예제 1: 등급별 회원 수와 평균 나이
SELECT
grade AS '등급',
COUNT(*) AS '회원수',
AVG(age) AS '평균나이',
MIN(age) AS '최소나이',
MAX(age) AS '최대나이'
FROM users
GROUP BY grade
ORDER BY COUNT(*) DESC;
-- 등급별로 묶어서 각종 통계 계산
예제 2: HAVING — 그룹 필터링 (집계 결과에 조건 적용)
-- 주문 수가 2건 이상인 회원의 총 주문금액
SELECT
user_id,
COUNT(*) AS '주문건수',
SUM(amount) AS '총주문금액'
FROM orders
GROUP BY user_id
HAVING COUNT(*) >= 2 -- WHERE는 그룹 전, HAVING은 그룹 후!
ORDER BY '총주문금액' DESC;
💡 WHERE vs HAVING 차이점 (자주 혼동!)
| 구분 | WHERE | HAVING |
|---|---|---|
| 적용 시점 | GROUP BY 전 | GROUP BY 후 |
| 사용 대상 | 개별 행(Row)에 조건 | 그룹(집계) 결과에 조건 |
| 집계함수 사용 | ❌ 불가 | ✅ 가능 |
| 예시 | WHERE age >= 30 | HAVING COUNT(*) >= 2 |
📌 SQL 실행 순서 (매우 중요!)
SQL은 작성 순서와 실행 순서가 다릅니다!
작성 순서
실행 순서
이 순서를 알면 왜 WHERE에서 SELECT의 별칭(AS)을 못 쓰는지, HAVING을 왜 따로 써야 하는지 이해됩니다!
실습 프로젝트 - 학생 성적 관리 시스템
🎯 프로젝트 목표
지금까지 배운 SELECT, WHERE, INSERT, UPDATE, DELETE, GROUP BY를 모두 활용하는 실전 프로젝트입니다. 학생 성적 관리 시스템의 DB를 직접 만들고 쿼리를 작성해보세요!
📐 데이터베이스 설계 (ERD 다이어그램)
PK: student_id
name, grade, class
birth_date, created_at
PK: score_id
FK: student_id
subject, score
exam_date
📌 실전 쿼리 요구사항 10문제
| 번호 | 요구사항 | 사용 기술 |
|---|---|---|
| Q1 | 전체 학생 목록을 이름 가나다 순으로 조회 | SELECT, ORDER BY |
| Q2 | 수학 점수가 80점 이상인 학생의 이름과 점수 조회 | WHERE, LIKE |
| Q3 | 학생별 평균점수, 최고점, 최저점 조회 (높은 순) | GROUP BY, AVG, MAX, MIN |
| Q4 | 과목별 평균점수와 응시인원 조회 | GROUP BY, COUNT, AVG |
| Q5 | 평균 점수가 80점 이상인 학생만 조회 | GROUP BY, HAVING |
| Q6 | 새 학생 '강다현' (3학년 C반) 등록 | INSERT INTO |
| Q7 | 박지훈의 국어 점수를 80점으로 수정 | UPDATE, WHERE |
| Q8 | 60점 미만 점수 데이터 전체 조회 | WHERE, ORDER BY |
| Q9 | 가장 최근 시험 날짜와 가장 오래된 시험 날짜 조회 | MAX, MIN |
| Q10 | 각 학생의 수학, 영어, 국어 점수를 한 행에 표시 | GROUP BY, MAX+CASE (피벗) |
정답 예시 (Q3, Q5, Q10)
-- Q3: 학생별 통계
SELECT st.name, ROUND(AVG(sc.score),1) AS avg_score,
MAX(sc.score) AS max_score, MIN(sc.score) AS min_score
FROM students st JOIN scores sc ON st.student_id = sc.student_id
GROUP BY st.student_id, st.name
ORDER BY avg_score DESC;
-- Q5: 평균 80 이상 학생
SELECT st.name, ROUND(AVG(sc.score),1) AS avg_score
FROM students st JOIN scores sc ON st.student_id = sc.student_id
GROUP BY st.student_id, st.name
HAVING AVG(sc.score) >= 80;
-- Q10: 피벗 테이블 (과목별 열로 전환)
SELECT
st.name,
MAX(CASE WHEN sc.subject = '수학' THEN sc.score END) AS math,
MAX(CASE WHEN sc.subject = '영어' THEN sc.score END) AS english,
MAX(CASE WHEN sc.subject = '국어' THEN sc.score END) AS korean
FROM students st JOIN scores sc ON st.student_id = sc.student_id
GROUP BY st.student_id, st.name;
현업 면접 SQL Q&A + 자주 쓰는 함수 모음
💼 현업 면접 단골 SQL 질문 TOP 8
🔧 현업에서 자주 쓰는 SQL 함수 완전 정리
| 함수 | 분류 | 기능 | 예시 |
|---|---|---|---|
| NOW() | 날짜/시간 | 현재 날짜+시간 | SET updated_at = NOW() |
| DATE(datetime) | 날짜/시간 | 날짜만 추출 | DATE(created_at) |
| YEAR/MONTH/DAY | 날짜/시간 | 년/월/일 추출 | YEAR(birth_date) = 2000 |
| CONCAT(a, b) | 문자열 | 문자열 연결 | CONCAT(first_name,' ',last_name) |
| LENGTH(str) | 문자열 | 문자열 바이트 길이 | WHERE LENGTH(password) >= 8 |
| SUBSTRING(str,s,l) | 문자열 | 부분 문자열 추출 | SUBSTRING(phone, 1, 3) |
| ROUND(n, d) | 수학 | 반올림 (d자리) | ROUND(AVG(score), 1) |
| FLOOR/CEIL | 수학 | 내림 / 올림 | FLOOR(price / 1000) |
| COALESCE(a,b) | NULL 처리 | 첫 번째 NULL이 아닌 값 | COALESCE(phone, '미등록') |
| IFNULL(a, b) | NULL 처리 | NULL이면 b 반환 | IFNULL(grade, '일반') |
| CASE WHEN | 조건 | IF-ELSE처럼 조건별 값 | CASE WHEN score >= 90 THEN 'A' |
📚 SQL 학습 로드맵 & 다음 단계
🗺️ DatabaseDevGuide 전체 로드맵
| 단계 | 학습 내용 | 기간 | 상태 |
|---|---|---|---|
| 1단계 | DB 개념 이해 - 테이블, 키, ACID, DBMS 비교 (Guide0001) | 1~2주 | ✅ 완료 |
| 2단계 | SQL 기초 - SELECT, WHERE, INSERT, UPDATE, DELETE, GROUP BY (Guide0002 - 현재) | 3~4주 | ✅ 현재 |
| 3단계 | SQL 심화 - JOIN, 서브쿼리, 인덱스, 뷰 (Guide0003) | 2~3주 | ⏳ 예정 |
| 4단계 | DB 설계 - 정규화, ERD, 쇼핑몰 DB 설계 (Guide0004) | 2~3주 | ⏳ 예정 |
| 5단계 | NoSQL 입문 - MongoDB, Redis (Guide0005) | 2주 | ⏳ 예정 |
| 6단계 | 실전 활용 - 백엔드 연동, ORM, 트랜잭션, 보안 (Guide0006) | 2주 | ⏳ 예정 |
| 7단계 | 실전 프로젝트 - 블로그/쇼핑몰 DB 전체 설계 및 구현 (Guide0007) | 3~4주 | ⏳ 예정 |
📌 SQL 실력 체크리스트 (이 가이드 완성 기준)
✅ 기본 SELECT
- SELECT, FROM, WHERE 자유롭게 사용
- ORDER BY, LIMIT으로 정렬/제한
- DISTINCT로 중복 제거
- AS로 별칭 지정
✅ 조건 필터링
- 비교연산자, IN, BETWEEN 활용
- LIKE 패턴 검색
- IS NULL / IS NOT NULL
- AND/OR 복합 조건
✅ 데이터 변경
- INSERT INTO (단건/다건)
- UPDATE SET WHERE
- DELETE FROM WHERE
- CASE WHEN 조건부 수정
✅ 집계 분석
- COUNT, SUM, AVG, MAX, MIN
- GROUP BY 그룹별 통계
- HAVING 그룹 필터
- SQL 실행 순서 이해
📚 추천 학습 자료 및 실습 사이트
| 사이트 | 특징 | 추천 대상 | 비용 |
|---|---|---|---|
| SQLZoo | 브라우저에서 바로 SQL 실행, 단계별 문제 | 완전 입문자 | 무료 |
| HackerRank SQL | 난이도별 SQL 문제 풀이, 즉시 채점 | 입문~중급 | 무료 |
| LeetCode Database | 실제 기업 면접 SQL 문제, 해설 풍부 | 취업 준비 | 무료(기본) |
| Mode Analytics | 실제 데이터로 SQL 분석, 데이터 분석가용 | 데이터 분석가 | 무료 |
| MySQL 공식 문서 | 모든 함수, 명령어 레퍼런스 | 레퍼런스용 | 무료 |
SQL 기초 완전 정복 완료!
SELECT, WHERE, ORDER BY, INSERT, UPDATE, DELETE, GROUP BY, DDL까지
모두 마스터했습니다! 이제 기본적인 DB 작업은 모두 할 수 있습니다.
📌 다음 단계: DatabaseDevGuide0003
SQL 심화 - JOIN(테이블 조인), 서브쿼리, 인덱스 전략, 뷰(View)