SQL 기초부터 실전까지 완벽 가이드 - 비전공자도 쉽게 배우는 데이터베이스
SQL Complete Guide from Basics to Practice - Database Learning for Non-Programmers
서론: 왜 SQL을 배워야 하는가?
2026년 현재, 우리는 매일 약 2.5엑사바이트(EB)의 데이터가 생성되는 시대에 살고 있습니다. 기업의 의사결정은 감에서 데이터 기반으로 전환되었고, 마케터는 고객 행동 데이터를 분석하며, 기획자는 서비스 사용 패턴을 숫자로 읽어냅니다. 이 모든 데이터 활용의 중심에 SQL(Structured Query Language)이 있습니다. SQL은 데이터베이스와 대화하기 위한 표준 언어로, 1970년대 IBM에서 처음 개발된 이후 반세기 넘게 데이터 관리의 핵심 도구로 자리잡고 있습니다.
"나는 개발자가 아닌데 SQL이 필요할까?"라고 묻는 분들이 많습니다. 답은 "예, 반드시 필요합니다"입니다. 디지털 마케터는 광고 성과 데이터를 직접 조회해야 하고, 서비스 기획자(PM)는 사용자 행동 로그를 분석하여 기능을 개선해야 합니다. 데이터 분석가는 물론이고, 인사담당자조차 직원 데이터를 효율적으로 관리하기 위해 SQL을 활용하는 시대가 되었습니다. 실제로 LinkedIn의 2025년 가장 수요가 높은 직무 스킬 보고서에 따르면, SQL은 프로그래밍 언어 중 가장 많은 채용 공고에서 요구되는 기술로 꼽혔습니다.
구체적으로 살펴보면, SQL을 활용할 수 있는 직군은 생각보다 훨씬 광범위합니다. 마케팅 담당자는 고객 세그먼트 분석, 캠페인 성과 측정, 이탈률 계산 등을 위해 SQL을 사용합니다. 서비스 기획자는 사용자 퍼널 분석, 기능 사용률 추적, A/B 테스트 결과 분석에 SQL을 활용합니다. 재무팀은 매출 추이 분석과 예산 집행 현황 파악에, 인사팀은 직원 현황 분석과 채용 데이터 관리에 SQL을 적용합니다. 이처럼 SQL은 특정 직군만의 전유물이 아니라, 데이터를 다루는 모든 현대 직장인의 기본 소양으로 자리잡아가고 있습니다.
좋은 소식은, SQL의 진입장벽이 매우 낮다는 것입니다. 영어 문장과 유사한 직관적인 문법 구조를 가지고 있어, 프로그래밍 경험이 전혀 없는 분도 기본 문법을 몇 시간 만에 익힐 수 있습니다. 예를 들어 "직원 테이블에서 마케팅 부서의 직원 이름을 급여 순으로 조회하라"는 요청을 SQL로 표현하면 SELECT name FROM employees WHERE department = '마케팅' ORDER BY salary DESC;가 됩니다. 마치 영어 문장을 읽듯이 자연스러운 구조를 가지고 있습니다. 이 글에서는 데이터베이스의 기초 개념부터 시작하여 실무에서 바로 활용할 수 있는 중급 기법까지, 비전공자의 눈높이에 맞추어 체계적으로 설명하겠습니다.
1. 데이터베이스 기초 개념
1.1 데이터베이스란?
데이터베이스(Database)란 체계적으로 구조화되어 저장된 데이터의 집합입니다. 단순한 파일 저장과 달리, 데이터베이스는 데이터를 효율적으로 저장, 검색, 수정, 삭제할 수 있도록 설계된 시스템입니다. 우리가 매일 사용하는 인터넷 쇼핑몰, 은행 서비스, SNS 등 거의 모든 디지털 서비스의 뒤편에는 데이터베이스가 작동하고 있습니다.
데이터베이스는 크게 두 가지 유형으로 나뉩니다:
- 관계형 데이터베이스(RDBMS): 데이터를 테이블(표) 형태로 저장하며, 테이블 간의 관계를 통해 데이터를 연결합니다. SQL을 사용하여 데이터를 조작합니다. 대표적으로 MySQL, PostgreSQL, Oracle, SQL Server, SQLite 등이 있습니다. 구조화된 데이터를 다루는 대부분의 업무에 적합합니다.
- 비관계형 데이터베이스(NoSQL): 테이블 구조에 얽매이지 않고 유연한 형태로 데이터를 저장합니다. MongoDB(문서형), Redis(키-값형), Cassandra(열 기반), Neo4j(그래프형) 등이 있으며, 대량의 비정형 데이터나 빠른 읽기/쓰기가 필요한 경우에 주로 사용됩니다.
이 글에서는 가장 널리 사용되고 취업 시장에서 높은 수요를 보이는 관계형 데이터베이스와 SQL에 집중하여 설명합니다. 특히 MySQL과 PostgreSQL은 오픈소스로 무료 사용이 가능하며 학습 자료도 풍부하여, 입문자에게 강력히 추천됩니다. 참고로 각 RDBMS의 특징을 간단히 비교하면, MySQL은 웹 서비스에서 가장 널리 사용되며 설치와 운영이 간편합니다. PostgreSQL은 표준 SQL을 가장 충실히 지원하고 고급 기능이 풍부합니다. Oracle은 대기업과 금융권에서 주로 사용되며 안정성이 뛰어나지만 상용 라이선스 비용이 높습니다. SQL Server는 마이크로소프트 생태계와의 호환성이 좋습니다. SQLite는 별도 서버 없이 파일 하나로 동작하여 모바일 앱이나 소규모 프로젝트에 적합합니다.
1.2 테이블, 행, 열 이해하기
관계형 데이터베이스의 핵심 구조는 테이블(Table)입니다. 엑셀을 사용해본 적이 있다면, 테이블을 쉽게 이해할 수 있습니다. 엑셀의 시트가 곧 테이블이고, 각 행(Row)은 하나의 데이터 레코드를, 각 열(Column)은 데이터의 속성(필드)을 나타냅니다.
예를 들어, 직원 정보를 관리하는 employees 테이블은 다음과 같은 구조를 가집니다:
| emp_id (직원번호) | name (이름) | department (부서) | salary (급여) | hire_date (입사일) |
|---|---|---|---|---|
| 1 | 김영희 | 마케팅 | 4500000 | 2023-03-15 |
| 2 | 이철수 | 개발 | 5200000 | 2022-07-01 |
| 3 | 박민수 | 인사 | 4000000 | 2024-01-10 |
데이터베이스에서 테이블 간의 관계를 설정하는 데 핵심적인 역할을 하는 두 가지 키(Key)가 있습니다:
- 기본키(Primary Key, PK): 각 행을 고유하게 식별하는 열입니다. 위 테이블에서
emp_id가 기본키에 해당합니다. 기본키는 중복이 허용되지 않으며 NULL 값을 가질 수 없습니다. 마치 주민등록번호처럼, 각 레코드를 유일하게 구분합니다. - 외래키(Foreign Key, FK): 다른 테이블의 기본키를 참조하는 열입니다. 예를 들어
orders(주문) 테이블에customer_id라는 열이 있다면, 이는customers(고객) 테이블의 기본키를 참조하는 외래키입니다. 외래키를 통해 테이블 간의 관계가 형성됩니다.
1.3 데이터 타입
데이터베이스의 각 열은 저장할 수 있는 데이터의 유형이 정해져 있습니다. 주요 데이터 타입은 다음과 같습니다:
| 분류 | 데이터 타입 | 설명 | 예시 |
|---|---|---|---|
| 정수 | INT, BIGINT | 정수 값 저장 | 1, 42, -100 |
| 실수 | DECIMAL, FLOAT | 소수점이 있는 숫자 | 3.14, 99.99 |
| 문자열 | VARCHAR(n), TEXT | 가변 길이 문자열 | '홍길동', 'hello' |
| 날짜 | DATE, DATETIME | 날짜 및 시간 | '2026-02-20' |
| 불리언 | BOOLEAN | 참/거짓 | TRUE, FALSE |
VARCHAR(n)은 최대 길이를 지정할 수 있어 이름, 이메일 등 길이가 예측 가능한 데이터에 적합합니다. TEXT는 길이 제한 없이 긴 문자열을 저장할 때 사용합니다. 일반적으로 구조화된 짧은 데이터에는 VARCHAR를, 게시글 본문 같은 긴 텍스트에는 TEXT를 사용합니다.
2. SQL 기본 문법 완전 정복
2.1 SELECT - 데이터 조회
SELECT는 SQL에서 가장 많이 사용되는 명령어로, 데이터베이스에서 원하는 데이터를 조회(읽기)하는 데 사용됩니다. SELECT 문의 기본 구조는 다음과 같습니다:
-- 기본 SELECT 문법
SELECT 열이름1, 열이름2
FROM 테이블이름
WHERE 조건
ORDER BY 정렬기준
LIMIT 개수;
실전 예시를 통해 하나씩 배워보겠습니다:
-- 1. 모든 직원 정보 조회
SELECT * FROM employees;
-- 2. 특정 열만 조회
SELECT name, department, salary
FROM employees;
-- 3. 조건 필터링 (WHERE)
-- 급여가 450만원 이상인 직원만 조회
SELECT name, department, salary
FROM employees
WHERE salary >= 4500000;
-- 4. 여러 조건 조합 (AND, OR)
-- 마케팅 부서이면서 급여가 400만원 이상인 직원
SELECT name, salary
FROM employees
WHERE department = '마케팅' AND salary >= 4000000;
-- 5. 정렬 (ORDER BY)
-- 급여 높은 순으로 정렬
SELECT name, salary
FROM employees
ORDER BY salary DESC;
-- 6. 결과 개수 제한 (LIMIT)
-- 급여 상위 5명만 조회
SELECT name, salary
FROM employees
ORDER BY salary DESC
LIMIT 5;
-- 7. 문자열 검색 (LIKE)
-- 이름이 '김'으로 시작하는 직원
SELECT * FROM employees
WHERE name LIKE '김%';
-- 8. 범위 검색 (BETWEEN)
-- 2023년에 입사한 직원
SELECT name, hire_date
FROM employees
WHERE hire_date BETWEEN '2023-01-01' AND '2023-12-31';
SQL은 작성 순서와 실행 순서가 다릅니다. 실제 실행 순서는: FROM(어떤 테이블에서?) -> WHERE(어떤 조건으로?) -> SELECT(어떤 열을?) -> ORDER BY(어떤 순서로?) -> LIMIT(몇 개를?) 입니다. 이 순서를 이해하면 복잡한 쿼리 작성 시 오류를 줄일 수 있습니다.
2.2 INSERT, UPDATE, DELETE - 데이터 조작
데이터베이스의 기본 작업을 CRUD라고 부릅니다. Create(생성), Read(읽기), Update(수정), Delete(삭제)의 약자로, SQL에서는 각각 INSERT, SELECT, UPDATE, DELETE 명령어에 대응합니다.
-- CREATE: 새 데이터 추가 (INSERT)
INSERT INTO employees (name, department, salary, hire_date)
VALUES ('정수연', '디자인', 4200000, '2026-02-20');
-- 여러 행을 한 번에 추가
INSERT INTO employees (name, department, salary, hire_date)
VALUES
('한지민', '마케팅', 4300000, '2026-01-15'),
('오세훈', '개발', 5500000, '2025-11-01'),
('최유리', '인사', 3800000, '2026-02-01');
-- UPDATE: 기존 데이터 수정
-- 김영희의 급여를 480만원으로 변경
UPDATE employees
SET salary = 4800000
WHERE name = '김영희';
-- 여러 열을 동시에 수정
UPDATE employees
SET department = '기획', salary = 4600000
WHERE emp_id = 3;
-- DELETE: 데이터 삭제
-- 특정 직원 삭제
DELETE FROM employees
WHERE emp_id = 5;
UPDATE employees SET salary = 0;이라고 실행하면 모든 직원의 급여가 0으로 변경됩니다. DELETE FROM employees;는 테이블의 모든 데이터를 삭제합니다. 실무에서는 반드시 WHERE 조건을 확인한 후 실행하고, 중요한 작업 전에는 트랜잭션(BEGIN/COMMIT/ROLLBACK)을 활용하세요.
2.3 집계 함수와 GROUP BY
집계 함수는 여러 행의 데이터를 하나의 결과로 요약하는 함수입니다. 데이터 분석에서 가장 자주 사용되는 핵심 기능입니다.
-- 기본 집계 함수
SELECT
COUNT(*) AS 전체직원수, -- 행의 개수
SUM(salary) AS 총급여합계, -- 합계
AVG(salary) AS 평균급여, -- 평균
MAX(salary) AS 최고급여, -- 최대값
MIN(salary) AS 최저급여 -- 최소값
FROM employees;
-- GROUP BY: 그룹별 집계
-- 부서별 평균 급여와 인원 수 구하기
SELECT
department AS 부서,
COUNT(*) AS 인원수,
ROUND(AVG(salary), 0) AS 평균급여,
MAX(salary) AS 최고급여,
MIN(salary) AS 최저급여
FROM employees
GROUP BY department
ORDER BY 평균급여 DESC;
-- HAVING: 그룹 조건 필터링
-- 평균 급여가 450만원 이상인 부서만 조회
SELECT
department AS 부서,
COUNT(*) AS 인원수,
ROUND(AVG(salary), 0) AS 평균급여
FROM employees
GROUP BY department
HAVING AVG(salary) >= 4500000
ORDER BY 평균급여 DESC;
WHERE vs HAVING의 차이는 SQL 초보자가 가장 혼동하기 쉬운 부분 중 하나입니다. 핵심 차이를 명확히 이해해봅시다. WHERE는 그룹화(GROUP BY) 전에 개별 행을 필터링하는 데 사용됩니다. 즉, 테이블의 원본 데이터에서 조건에 맞는 행만 먼저 걸러냅니다. 반면 HAVING은 GROUP BY로 그룹화된 이후에 그룹 단위로 필터링합니다. 따라서 HAVING 절에서는 집계 함수(COUNT, SUM, AVG 등)를 조건으로 사용할 수 있지만, WHERE 절에서는 집계 함수를 직접 사용할 수 없습니다. 예를 들어 "급여가 300만원 이상인 직원들만 대상으로, 부서별 평균급여가 450만원 이상인 부서"를 구하려면 WHERE와 HAVING을 함께 사용합니다:
SELECT department, ROUND(AVG(salary), 0) AS avg_salary
FROM employees
WHERE salary >= 3000000 -- 개별 행 필터 (그룹화 전)
GROUP BY department
HAVING AVG(salary) >= 4500000 -- 그룹 필터 (그룹화 후)
ORDER BY avg_salary DESC;
3. 중급 SQL - 실무에서 많이 쓰는 기법
3.1 JOIN - 테이블 연결의 핵심
실무에서는 데이터가 여러 테이블에 나누어 저장되어 있습니다. 앞서 정규화에서 배운 것처럼, 좋은 데이터베이스 설계는 데이터를 목적에 맞게 여러 테이블로 분리합니다. 하지만 분석이나 보고서 작성 시에는 분리된 데이터를 다시 결합하여 의미 있는 정보를 추출해야 합니다. JOIN은 두 개 이상의 테이블을 연결하여 관련된 데이터를 함께 조회하는 기능으로, SQL에서 가장 중요한 중급 개념입니다. JOIN을 자유자재로 활용할 수 있다면, SQL 실력이 초급에서 중급으로 도약했다고 말할 수 있습니다. 많은 실무 쿼리가 JOIN을 기반으로 작성되며, 채용 면접에서도 JOIN의 이해도를 평가하는 문제가 자주 출제됩니다.
다음과 같은 두 테이블이 있다고 가정합니다:
-- employees (직원) 테이블
-- emp_id | name | dept_id
-- 1 | 김영희 | 10
-- 2 | 이철수 | 20
-- 3 | 박민수 | 10
-- 4 | 최지은 | NULL
-- departments (부서) 테이블
-- dept_id | dept_name
-- 10 | 마케팅
-- 20 | 개발
-- 30 | 인사
JOIN의 종류를 벤 다이어그램 개념으로 이해해봅시다:
INNER JOIN LEFT JOIN RIGHT JOIN FULL OUTER JOIN
A B A B A B A B
/ \ / \ / \ / \ / \ / \ / \ / \
| .|X|. | | |X| | | |X| | | |X| |
\ / \ / \ / \ / \ / \ / \ / \ /
양쪽 모두 왼쪽 전체 오른쪽 전체 양쪽 전체
일치하는 것만 + 오른쪽 일치 + 왼쪽 일치 모두 포함
-- INNER JOIN: 양쪽 테이블에 모두 매칭되는 데이터만 조회
-- 결과: 김영희(마케팅), 이철수(개발), 박민수(마케팅)
-- 최지은(dept_id=NULL)과 인사 부서(매칭 직원 없음)는 제외
SELECT e.name, d.dept_name
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id;
-- LEFT JOIN: 왼쪽 테이블의 모든 행 + 오른쪽 테이블 매칭
-- 결과: 모든 직원 표시, 최지은의 부서는 NULL로 표시
SELECT e.name, d.dept_name
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.dept_id;
-- RIGHT JOIN: 오른쪽 테이블의 모든 행 + 왼쪽 테이블 매칭
-- 결과: 모든 부서 표시, 인사 부서의 직원은 NULL로 표시
SELECT e.name, d.dept_name
FROM employees e
RIGHT JOIN departments d ON e.dept_id = d.dept_id;
-- FULL OUTER JOIN: 양쪽 테이블의 모든 행 포함
-- (MySQL에서는 UNION으로 구현)
SELECT e.name, d.dept_name
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.dept_id
UNION
SELECT e.name, d.dept_name
FROM employees e
RIGHT JOIN departments d ON e.dept_id = d.dept_id;
실무에서 가장 자주 사용되는 JOIN 실전 예시를 살펴보겠습니다:
-- 실전: 고객별 주문 내역과 총 주문 금액 조회
SELECT
c.customer_name AS 고객명,
COUNT(o.order_id) AS 주문건수,
SUM(o.amount) AS 총주문금액
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.customer_name
ORDER BY 총주문금액 DESC;
-- 실전: 3개 테이블 JOIN - 주문 상세 내역
SELECT
c.customer_name AS 고객명,
o.order_date AS 주문일,
p.product_name AS 상품명,
od.quantity AS 수량,
od.unit_price AS 단가,
(od.quantity * od.unit_price) AS 소계
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id
INNER JOIN order_details od ON o.order_id = od.order_id
INNER JOIN products p ON od.product_id = p.product_id
WHERE o.order_date >= '2026-01-01'
ORDER BY o.order_date DESC;
3.2 서브쿼리와 CTE
서브쿼리(Subquery)는 SQL 문 안에 포함된 또 다른 SQL 문입니다. 복잡한 조건이나 계산이 필요한 경우에 유용합니다.
-- 서브쿼리 기본: 평균 급여보다 높은 직원 조회
SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
-- IN 서브쿼리: 주문 이력이 있는 고객만 조회
SELECT customer_name
FROM customers
WHERE customer_id IN (
SELECT DISTINCT customer_id FROM orders
);
-- EXISTS 서브쿼리: 특정 조건을 만족하는 행 존재 여부 확인
SELECT d.dept_name
FROM departments d
WHERE EXISTS (
SELECT 1 FROM employees e
WHERE e.dept_id = d.dept_id AND e.salary > 5000000
);
CTE(Common Table Expression)는 WITH 절을 사용하여 임시 결과 집합에 이름을 부여하는 방법입니다. 복잡한 서브쿼리를 읽기 쉽고 재사용 가능하게 만들어줍니다.
-- CTE 기본 문법
WITH 임시테이블명 AS (
SELECT 문
)
SELECT * FROM 임시테이블명;
-- 실전: 평균 이상 매출 고객 찾기
WITH customer_sales AS (
SELECT
c.customer_id,
c.customer_name,
SUM(o.amount) AS total_sales
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.customer_name
),
avg_sales AS (
SELECT AVG(total_sales) AS avg_total
FROM customer_sales
)
SELECT
cs.customer_name AS 고객명,
cs.total_sales AS 총매출,
a.avg_total AS 전체평균,
ROUND(cs.total_sales / a.avg_total * 100, 1) AS 평균대비_퍼센트
FROM customer_sales cs
CROSS JOIN avg_sales a
WHERE cs.total_sales > a.avg_total
ORDER BY cs.total_sales DESC;
단순한 조건에는 서브쿼리가 간결합니다. 하지만 같은 결과를 여러 번 참조하거나, 쿼리가 길어져 가독성이 떨어질 때는 CTE를 사용하세요. CTE는 쿼리를 마치 단락별로 나눈 글처럼 읽기 쉽게 만들어줍니다. 실무에서는 CTE 사용이 점점 더 권장되는 추세입니다.
3.3 윈도우 함수
윈도우 함수(Window Function)는 행 그룹에 대해 계산을 수행하면서도 개별 행을 유지하는 강력한 기능입니다. GROUP BY와 달리 행을 합치지 않고, 각 행에 대한 계산 결과를 추가로 표시합니다. 윈도우 함수는 데이터 분석에서 매우 빈번하게 사용되며, "부서 내에서 급여 순위는?", "전월 대비 매출 증감은?", "누적 합계는?" 같은 질문에 우아하게 답할 수 있는 도구입니다. 윈도우 함수를 활용하면 기존에 서브쿼리나 셀프 조인으로 복잡하게 작성해야 했던 쿼리를 훨씬 간결하고 읽기 쉽게 표현할 수 있습니다. 면접에서 윈도우 함수를 자연스럽게 사용할 수 있다면, SQL 중급 이상의 실력자로 인정받을 수 있습니다.
-- ROW_NUMBER(): 순번 부여
-- 부서별로 급여 높은 순서대로 순번 부여
SELECT
name,
department,
salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS 부서내순위
FROM employees;
-- RANK(): 순위 부여 (동순위 허용, 다음 순위 건너뜀)
-- DENSE_RANK(): 순위 부여 (동순위 허용, 다음 순위 건너뛰지 않음)
SELECT
name,
salary,
RANK() OVER (ORDER BY salary DESC) AS rank_순위,
DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rank_순위
FROM employees;
-- 실전: 월별 매출과 순위
SELECT
DATE_FORMAT(order_date, '%Y-%m') AS 월,
SUM(amount) AS 월매출,
RANK() OVER (ORDER BY SUM(amount) DESC) AS 매출순위
FROM orders
WHERE order_date >= '2025-01-01'
GROUP BY DATE_FORMAT(order_date, '%Y-%m')
ORDER BY 월;
-- LAG() / LEAD(): 이전행/다음행 참조
-- 실전: 전월 대비 매출 성장률 계산
WITH monthly_sales AS (
SELECT
DATE_FORMAT(order_date, '%Y-%m') AS month,
SUM(amount) AS sales
FROM orders
WHERE order_date >= '2025-01-01'
GROUP BY DATE_FORMAT(order_date, '%Y-%m')
)
SELECT
month AS 월,
sales AS 당월매출,
LAG(sales, 1) OVER (ORDER BY month) AS 전월매출,
ROUND(
(sales - LAG(sales, 1) OVER (ORDER BY month))
/ LAG(sales, 1) OVER (ORDER BY month) * 100, 1
) AS 성장률_퍼센트
FROM monthly_sales
ORDER BY month;
윈도우 함수의 핵심 구문은 함수() OVER (PARTITION BY 그룹열 ORDER BY 정렬열)입니다. PARTITION BY는 GROUP BY와 유사하게 그룹을 지정하지만, 행을 합치지 않고 각 행에 결과를 표시합니다. ORDER BY는 윈도우 내에서의 정렬 순서를 결정합니다.
4. 데이터베이스 설계 기초
좋은 데이터베이스 설계는 데이터의 일관성, 효율성, 확장성을 보장합니다. 아무리 SQL 문법을 잘 알더라도, 데이터베이스 구조가 잘못 설계되어 있으면 쿼리 성능이 저하되고 데이터 불일치 문제가 발생합니다. 마치 건물의 기초 공사와 같아서, 초기에 올바른 설계를 하지 않으면 나중에 수정하는 비용이 기하급수적으로 증가합니다. 실무에서 자주 발생하는 문제를 예로 들면, 하나의 테이블에 모든 정보를 때려 넣는 "만능 테이블" 설계가 있습니다. 이런 구조는 처음에는 간편해 보이지만, 데이터가 쌓일수록 중복이 심해지고, 수정 시 여러 곳을 동시에 변경해야 하는 번거로움이 발생합니다.
설계의 핵심 원칙인 정규화(Normalization)를 쉽게 이해해봅시다.
정규화란? 데이터 중복을 줄이고 데이터 무결성을 높이기 위해 테이블을 체계적으로 분리하는 과정입니다. 정규화가 왜 필요한지 간단한 예시로 살펴보겠습니다. 만약 주문 테이블에 고객 이름과 고객 주소를 함께 저장한다면, 같은 고객이 여러 번 주문할 때마다 이름과 주소가 반복 저장됩니다. 이 고객이 주소를 변경하면, 모든 주문 레코드를 찾아 수정해야 합니다. 하나라도 놓치면 데이터 불일치가 발생합니다. 정규화는 이런 문제를 구조적으로 방지합니다.
- 제1정규형(1NF): 각 셀에 하나의 값만 저장합니다. "서울, 부산"처럼 하나의 셀에 여러 값을 넣지 않습니다. 모든 열의 값이 원자적(Atomic)이어야 합니다.
- 제2정규형(2NF): 1NF를 만족하면서, 기본키가 아닌 모든 열이 기본키 전체에 종속되어야 합니다. 기본키의 일부에만 종속되는 열은 별도 테이블로 분리합니다. 예를 들어, 주문 테이블에서 상품명은 주문번호가 아닌 상품번호에 종속되므로 분리합니다.
- 제3정규형(3NF): 2NF를 만족하면서, 기본키가 아닌 열이 다른 비기본키 열에 종속되지 않아야 합니다. 예를 들어, 직원 테이블에 부서명과 부서위치가 함께 있다면, 부서위치는 부서명에 종속되므로 부서 테이블로 분리합니다.
ERD(Entity-Relationship Diagram)는 테이블 간의 관계를 시각적으로 표현한 다이어그램입니다. ERD를 읽는 기본 방법은 다음과 같습니다:
- 사각형: 엔티티(테이블)
- 선: 관계 (1:1, 1:N, N:M)
- PK: 기본키 표시
- FK: 외래키 표시 (다른 테이블을 참조)
-- ERD 텍스트 표현 예시
+---------------+ +------------------+ +----------------+
| customers | | orders | | products |
+---------------+ +------------------+ +----------------+
| PK customer_id|---+ | PK order_id | +---| PK product_id |
| name | +-->| FK customer_id | | | name |
| email | | order_date | | | price |
| phone | | total_amount | | | category |
+---------------+ +------------------+ | +----------------+
| order_details | |
+------------------+ |
| PK detail_id | |
| FK order_id | |
| FK product_id |---+
| quantity |
| unit_price |
+------------------+
1. 하나의 테이블은 하나의 주제만 다룬다 (단일 책임 원칙)
2. 기본키는 반드시 설정한다 (자동 증가 정수 또는 UUID 추천)
3. 열 이름은 일관된 명명 규칙을 따른다 (snake_case 추천)
4. NULL 허용 여부를 신중하게 결정한다
5. 인덱스를 적절히 활용하여 검색 성능을 최적화한다
5. 실습 환경 구축 가이드
SQL을 배우려면 직접 쿼리를 실행해보는 것이 가장 효과적입니다. 이론만 읽어서는 SQL을 제대로 익힐 수 없습니다. 프로그래밍 학습에서 가장 중요한 원칙은 "읽는 것보다 직접 타이핑하라"는 것이며, SQL도 마찬가지입니다. 쿼리를 직접 작성하고, 결과를 확인하고, 조건을 바꿔가며 실험하는 과정에서 진정한 이해가 생깁니다. 설치 없이 바로 시작할 수 있는 온라인 환경부터, 본격적인 학습을 위한 로컬 환경까지 소개합니다.
온라인 무료 실습 환경 (설치 불필요)
- SQLite Online (sqliteonline.com): 웹 브라우저에서 바로 SQL을 실행할 수 있습니다. SQLite, PostgreSQL, MySQL 문법을 모두 지원하며, 별도 가입 없이 즉시 사용 가능합니다. 초보자에게 가장 추천하는 환경입니다.
- DB Fiddle (db-fiddle.com): MySQL, PostgreSQL, SQLite를 지원하며, 작성한 쿼리를 URL로 공유할 수 있어 협업이나 질문 시 유용합니다.
- W3Schools SQL Tryit Editor: 샘플 데이터가 미리 준비되어 있어, 각 SQL 문법을 바로 실습해볼 수 있습니다. 튜토리얼과 함께 제공되어 학습과 실습을 동시에 진행할 수 있습니다.
- LeetCode / HackerRank SQL 문제: 실전 문제를 풀면서 SQL 실력을 키울 수 있는 코딩 플랫폼입니다. 난이도별 문제가 잘 분류되어 있어 단계적 학습에 적합합니다.
로컬 설치 환경 (본격 학습용)
- MySQL + MySQL Workbench: 가장 널리 사용되는 오픈소스 RDBMS입니다. MySQL Workbench는 공식 GUI 도구로, 시각적으로 데이터베이스를 관리하고 쿼리를 작성할 수 있습니다. 웹 개발 학습 시 특히 추천됩니다.
- PostgreSQL + pgAdmin: 고급 기능이 풍부한 오픈소스 RDBMS입니다. 표준 SQL을 가장 충실히 지원하며, 데이터 분석이나 백엔드 개발에 많이 사용됩니다. pgAdmin은 웹 기반 관리 도구입니다.
- DBeaver (범용 DB 클라이언트): MySQL, PostgreSQL, Oracle, SQL Server 등 거의 모든 데이터베이스에 연결할 수 있는 무료 범용 도구입니다. 하나의 도구로 여러 DBMS를 다루고 싶을 때 추천합니다.
연습용 샘플 데이터셋
SQL을 효과적으로 학습하려면 실제와 유사한 구조의 데이터로 연습하는 것이 중요합니다. 다음은 널리 사용되는 무료 샘플 데이터셋입니다. 각각 서로 다른 비즈니스 도메인을 모델링하고 있어, 다양한 상황에서의 쿼리 작성을 연습할 수 있습니다:
- Northwind Database: 무역 회사의 주문, 고객, 상품, 공급업체 데이터로 구성된 클래식 학습용 데이터셋입니다. 고객별 주문 분석, 상품 카테고리별 매출 집계, 공급업체 성과 비교 등 실무에서 자주 접하는 유형의 쿼리를 연습할 수 있습니다. JOIN, 집계, 서브쿼리 연습에 최적입니다.
- Sakila Database: DVD 대여점을 모델링한 MySQL 공식 샘플 데이터베이스입니다. 영화, 배우, 고객, 대여 기록 등 다양한 테이블 간의 관계가 잘 구성되어 있어, 다중 테이블 조인과 복잡한 쿼리 연습에 적합합니다.
- Chinook Database: 디지털 음악 스토어를 모델링한 데이터셋으로, SQLite용으로도 제공되어 가볍게 시작하기 좋습니다. 아티스트, 앨범, 트랙, 송장 등의 테이블로 구성되며, 음악 스트리밍 서비스와 유사한 데이터 분석을 경험할 수 있습니다.
6. SQL 학습 로드맵 및 자격증
SQL 학습에서 가장 흔한 실수는 처음부터 너무 많은 것을 한꺼번에 배우려는 것입니다. 기본 문법도 완전히 숙달되지 않은 상태에서 윈도우 함수나 최적화 기법을 공부하면, 오히려 혼란만 가중됩니다. 가장 효과적인 학습법은 단계별로 차근차근 진행하면서, 각 단계의 내용을 충분히 연습한 후 다음 단계로 넘어가는 것입니다. 체계적인 학습을 위한 4주 로드맵을 제안합니다. 하루 1~2시간 투자를 기준으로 구성했습니다.
| 주차 | 학습 목표 | 주요 내용 | 실습 과제 |
|---|---|---|---|
| 1주차 | 기초 문법 마스터 | SELECT, WHERE, ORDER BY, LIMIT, INSERT, UPDATE, DELETE | W3Schools 전체 기본 문제 풀기 |
| 2주차 | 집계와 그룹화 | 집계 함수, GROUP BY, HAVING, DISTINCT, 날짜 함수 | Northwind DB로 매출 분석 보고서 작성 |
| 3주차 | JOIN과 서브쿼리 | INNER/LEFT/RIGHT JOIN, 서브쿼리, CTE, UNION | LeetCode Easy~Medium SQL 문제 20개 |
| 4주차 | 실전 응용 | 윈도우 함수, 테이블 생성, 인덱스, 뷰, 트랜잭션 | 실제 업무 데이터 분석 미니 프로젝트 |
SQLD (SQL 개발자) 자격증
SQLD(SQL Developer)는 한국데이터산업진흥원에서 시행하는 국가공인 자격증으로, SQL 활용 능력을 공식적으로 인증받을 수 있습니다. 비전공자의 데이터 역량을 증명하는 데 매우 효과적이며, IT 기업 취업이나 부서 이동 시 유리하게 작용합니다. 특히 데이터 분석가, 데이터 엔지니어, 백엔드 개발자 등의 직무를 목표로 하는 분들에게는 이력서에 SQLD 자격증을 기재하는 것만으로도 기본적인 데이터베이스 역량을 갖추고 있음을 증명할 수 있습니다. 상위 자격증인 SQLP(SQL 전문가)도 있으니, SQLD 취득 후 심화 학습을 원하는 분은 도전해보시기 바랍니다.
- 시험 구성: 데이터 모델링의 이해(10문항), SQL 기본 및 활용(40문항), 총 50문항 객관식
- 합격 기준: 총점 60점 이상, 과목별 40% 이상
- 시험 일정: 연 4회(3월, 6월, 9월, 12월), 접수는 한국데이터산업진흥원 홈페이지
- 준비 기간: 비전공자 기준 약 4~8주, SQL 기본 지식이 있다면 2~4주
추천 학습 리소스
- 무료: W3Schools SQL Tutorial, Mode Analytics SQL Tutorial, Khan Academy SQL 강의, SQLZoo Interactive Tutorial
- 유료: 인프런/패스트캠퍼스 SQL 강의(한국어), Udemy "The Complete SQL Bootcamp", DataCamp SQL Track
- 서적: "모두의 SQL"(김영보), "SQL 첫걸음"(아사이 아츠시), "SQL 코딩의 기술"(존 비에스카스)
결론: SQL은 가장 가성비 좋은 기술 투자
SQL은 반세기 넘게 사용되어온 검증된 기술이면서, 동시에 데이터 시대의 핵심 역량입니다. Python이나 JavaScript 같은 프로그래밍 언어에 비해 문법이 단순하고, 배우는 데 걸리는 시간 대비 실무 활용도가 매우 높습니다. 마케터, 기획자, 데이터 분석가, 백엔드 개발자 등 데이터를 다루는 모든 직군에서 SQL은 공통 언어로 사용됩니다. 실제로 많은 기업에서 비개발 직군의 채용 공고에도 SQL 활용 능력을 우대 사항이 아닌 필수 요건으로 기재하는 추세입니다. 특히 스타트업이나 데이터 기반 의사결정을 중시하는 조직에서는, 개발팀에 데이터 조회를 요청하지 않고 스스로 필요한 데이터를 추출할 수 있는 인재를 선호합니다.
이 글에서 다룬 내용을 요약하면 다음과 같습니다:
- 기초 개념: 데이터베이스, 테이블, 행, 열, 기본키, 외래키의 관계를 이해합니다.
- 기본 문법: SELECT로 데이터를 조회하고, INSERT/UPDATE/DELETE로 데이터를 조작합니다.
- 집계와 그룹화: COUNT, SUM, AVG 등 집계 함수와 GROUP BY로 데이터를 요약합니다.
- JOIN: 여러 테이블을 연결하여 관계된 데이터를 함께 조회합니다.
- 서브쿼리와 CTE: 복잡한 조건과 다단계 분석을 구현합니다.
- 윈도우 함수: 순위, 이전/다음행 비교 등 고급 분석을 수행합니다.
- 데이터베이스 설계: 정규화를 통해 효율적이고 일관된 데이터 구조를 만듭니다.
Step 1: SQLite Online(sqliteonline.com)에 접속하여
SELECT 'Hello, SQL!' AS greeting;을 실행해보세요. 축하합니다, 첫 번째 쿼리를 실행했습니다!Step 2: W3Schools SQL Tutorial에서 SELECT, WHERE, ORDER BY 챕터를 따라하며 샘플 데이터로 직접 쿼리를 작성해보세요. 30분이면 기본 조회를 할 수 있습니다.
Step 3: 본인의 업무와 관련된 질문을 SQL로 표현해보세요. "이번 달 매출이 가장 높은 상품 TOP 10은?" "지난 분기 대비 신규 고객 수 변화는?" 이런 질문을 SQL로 바꾸는 연습이 실력 향상의 핵심입니다.
SQL 핵심 구문 치트시트
| 구분 | 구문 | 설명 |
|---|---|---|
| 조회 | SELECT 열 FROM 테이블 |
데이터 조회 |
| 조건 | WHERE 조건 |
행 필터링 |
| 정렬 | ORDER BY 열 ASC/DESC |
오름차순/내림차순 정렬 |
| 제한 | LIMIT n |
결과 개수 제한 |
| 삽입 | INSERT INTO 테이블 VALUES (...) |
새 데이터 추가 |
| 수정 | UPDATE 테이블 SET 열=값 WHERE 조건 |
기존 데이터 수정 |
| 삭제 | DELETE FROM 테이블 WHERE 조건 |
데이터 삭제 |
| 집계 | COUNT, SUM, AVG, MAX, MIN |
그룹 함수 |
| 그룹 | GROUP BY 열 HAVING 조건 |
그룹별 집계 및 필터 |
| 연결 | JOIN 테이블 ON 조건 |
테이블 결합 |
| 임시 | WITH cte AS (SELECT ...) |
CTE (공통 테이블 표현식) |
| 순위 | ROW_NUMBER() OVER (...) |
윈도우 함수 |
SQL은 한 번 배우면 평생 써먹을 수 있는, 가장 가성비 좋은 기술 투자입니다. 데이터가 곧 경쟁력인 시대에, SQL을 통해 데이터와 직접 대화할 수 있는 능력을 갖추는 것은 어떤 직군에서든 강력한 무기가 될 것입니다. 또한 SQL을 익히는 과정에서 자연스럽게 데이터 구조에 대한 이해, 논리적 사고력, 문제 해결 능력이 함께 성장합니다. 이는 SQL 그 자체를 넘어서 다른 기술 학습의 토대가 되며, 엑셀만으로는 한계가 있는 대용량 데이터 분석의 문을 열어줍니다. SQL은 기술의 유행에 휩쓸리지 않는, 시대를 초월한 기본기입니다. 오늘 첫 번째 쿼리를 실행하는 것부터 시작하세요. 그 작은 첫걸음이 여러분의 커리어에 놀라운 변화를 가져올 것입니다.