SQL 명령어 실행 순서
실제 실행 순서
- FROM - 테이블 지정 및 조인
- WHERE - 행 필터링 (집계 전)
- GROUP BY - 그룹화
- HAVING - 그룹 필터링 (집계 후)
- SELECT - 컬럼 선택 및 계산
- DISTINCT - 중복 제거
- ORDER BY - 정렬
- LIMIT/OFFSET - 결과 개수 제한
예시
SELECT department, COUNT(*) as emp_count
FROM employees
WHERE salary > 3000 -- 집계함수 사용 불가
GROUP BY department
HAVING COUNT(*) > 5 -- 집계함수 사용 가능
ORDER BY emp_count DESC
LIMIT 10;
- FROM employees - employees 테이블 가져오기
- WHERE salary > 3000 - 급여 3000 초과인 직원만 필터링
- GROUP BY department - 부서별로 그룹화
- HAVING COUNT(*) > 5 - 직원 수가 5명 초과인 그룹만 선택
- SELECT department, COUNT(*) - 부서명과 직원 수 계산
- ORDER BY emp_count DESC - 직원 수 내림차순 정렬
- LIMIT 10 - 상위 10개만 반환
CASE WHEN 조건문
CASE
WHEN 조건1 THEN 결과1
WHEN 조건2 THEN 결과2
ELSE 기본결과 -- 생략 가능 생략 시 자동으로 NULL
END
예시 - 급여 등급 분류
SELECT
name,
salary,
CASE
WHEN salary >= 7000 THEN '고급'
WHEN salary >= 5000 THEN '중급'
ELSE '초급'
END AS grade
FROM employees;
문자열 처리 - CONCAT 함수
-- CONCAT: 여러 문자열 연결
SELECT CONCAT('Hello', ' ', 'World'); -- 'Hello World'
-- CONCAT_WS: 구분자를 사용한 연결 (Concat With Separator)
SELECT CONCAT_WS('-', '2024', '10', '26'); -- '2024-10-26'
-- NULL 처리: 하나라도 NULL이면 결과가 NULL
SELECT CONCAT('Hello', NULL, 'World'); -- NULL
DATE 처리
-- 날짜 추출
YEAR(date) -- 연도
MONTH(date) -- 월
DAY(date) -- 일
QUARTER(date) -- 분기
-- 현재 날짜
CURDATE() -- 오늘 날짜
NOW() -- 현재 날짜+시간
-- 포맷팅
DATE_FORMAT(date, '%Y-%m-%d') -- 날짜 형식 변환
-- 연산
DATE_ADD(date, INTERVAL n DAY/MONTH/YEAR) -- 날짜 더하기
DATEDIFF(date1, date2) -- 날짜 차이
-- 변환
DATE(datetime) -- datetime → date
STR_TO_DATE(str, format) -- 문자열 → 날짜
-- 비교 (성능 중요!)
✅ WHERE date >= '2021-01-01' AND date < '2022-01-01' --인덱스 사용가능
⚠️ WHERE YEAR(date) = 2021 --인덱스 사용불가
LIKE
1. % 와일드카드 (여러 문자)
-- 'A'로 시작하는 모든 문자열
SELECT * FROM ITEM_INFO
WHERE NAME LIKE 'A%';
-- 'A'로 끝나는 모든 문자열
SELECT * FROM ITEM_INFO
WHERE NAME LIKE '%A';
-- 'A'가 포함된 모든 문자열
SELECT * FROM ITEM_INFO
WHERE NAME LIKE '%A%';
-- 'A'로 시작하고 'Z'로 끝나는 문자열
SELECT * FROM ITEM_INFO
WHERE NAME LIKE 'A%Z';
2. _ 와일드카드 (한 글자)
-- 정확히 3글자인 문자열
SELECT * FROM ITEM_INFO
WHERE NAME LIKE '___';
-- 'A'로 시작하는 3글자 문자열
SELECT * FROM ITEM_INFO
WHERE NAME LIKE 'A__';
-- 두 번째 글자가 'A'인 문자열
SELECT * FROM ITEM_INFO
WHERE NAME LIKE '_A%';
NULL 처리
예시
https://school.programmers.co.kr/learn/courses/30/lessons/293259
-- 1. CASE 직접 사용 (가장 간단) ✅
SELECT ROUND(AVG(CASE WHEN LENGTH IS NULL THEN 10 ELSE LENGTH END), 2) AS AVERAGE_LENGTH
FROM FISH_INFO;
-- 2. COALESCE 사용 (더 간결) ✅
SELECT ROUND(AVG(COALESCE(LENGTH, 10)), 2) AS AVERAGE_LENGTH
FROM FISH_INFO;
서브쿼리
1. WHERE 절 서브쿼리
-- 단일 값 비교
SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
-- IN 사용
SELECT name, department_id
FROM employees
WHERE department_id IN (SELECT id FROM departments WHERE location = 'Seoul');
-- EXISTS 사용
SELECT name
FROM employees e
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.employee_id = e.id);
2. FROM 절 서브쿼리
SELECT dept_name, avg_salary
FROM (
SELECT department_id, AVG(salary) as avg_salary
FROM employees
GROUP BY department_id
) dept_avg
JOIN departments d ON dept_avg.department_id = d.id;
3. SELECT 절 서브쿼리
SELECT
name,
salary,
(SELECT AVG(salary) FROM employees) as company_avg,
(SELECT COUNT(*) FROM orders WHERE employee_id = e.id) as order_count
FROM employees e;
DISTINCT
-- 중복 제거된 단일 컬럼
SELECT DISTINCT department_id
FROM employees;
-- 중복 제거된 개수
SELECT COUNT(DISTINCT department_id) as dept_count
FROM employees;
-- 부서별 고유한 직책 수
SELECT
department_id,
COUNT(DISTINCT job_title) as unique_jobs
FROM employees
GROUP BY department_id;
-- DISTINCT 대신 GROUP BY 사용 (때로는 더 효율적)
SELECT department_id
FROM employees
GROUP BY department_id;