SQL 튜터 세션 정리
SQL
프로그래머스
CASE WHEN, HAVING, COALESCE, MAX + INNER JOIN 패턴 등 핵심 SQL 개념 (5문제)
SQL 튜터 세션 정리
날짜: 2026-04-16
오늘 푼 문제
| # | 문제 | 핵심 개념 |
|---|---|---|
| 1 | 대장균 크기 LOW/MEDIUM/HIGH 분류 | CASE WHEN |
| 2 | 물고기 평균 길이 필터링 | CTE, COALESCE, AVG, HAVING |
| 3 | 물고기 종류별 최대 크기 ID 출력 | 다중 CTE, MAX + INNER JOIN으로 원본 행 복원 |
| 4 | 부서별 평균 연봉 조회 | AVG, ROUND, GROUP BY, JOIN |
| 5 | 사원별 성과금 정보 조회 | 다중 테이블 JOIN, CASE WHEN 중첩 |
풀이 코드
1. 대장균 크기 LOW/MEDIUM/HIGH 분류
SELECT ID,
CASE WHEN SIZE_OF_COLONY <= 100 THEN 'LOW'
WHEN SIZE_OF_COLONY <= 1000 THEN 'MEDIUM'
ELSE 'HIGH' END AS SIZE
FROM ECOLI_DATA
ORDER BY ID ASC;주의:
ELSE THEN 'HIGH'(X) →ELSE 'HIGH'(O) — ELSE 뒤에는 THEN 없음
2. 물고기 평균 길이 필터링 (33cm 이상)
WITH T1 AS (
SELECT ID,
FISH_TYPE,
COALESCE(LENGTH, 10) AS LENGTH -- NULL은 10cm로 대체
FROM FISH_INFO
)
SELECT COUNT(ID) AS FISH_COUNT, MAX(LENGTH) AS MAX_LENGTH, FISH_TYPE
FROM T1
GROUP BY FISH_TYPE
HAVING AVG(LENGTH) >= 33
ORDER BY FISH_TYPE;핵심: 집계 함수가 조건에 들어가면
WHERE대신HAVING
3. 물고기 종류별 최대 크기 ID 출력
WITH max_by_type AS (
SELECT FISH_TYPE, MAX(COALESCE(LENGTH, 0)) AS MAX_LENGTH
FROM FISH_INFO
GROUP BY FISH_TYPE
),
target AS (
SELECT F.ID, F.FISH_TYPE, F.LENGTH
FROM FISH_INFO F
INNER JOIN max_by_type M
ON F.FISH_TYPE = M.FISH_TYPE
AND F.LENGTH = M.MAX_LENGTH
)
SELECT ID, FI.FISH_NAME, LENGTH
FROM target
LEFT JOIN FISH_NAME_INFO FI ON target.FISH_TYPE = FI.FISH_TYPE
ORDER BY ID;패턴:
GROUP BY만으로는 ID 보장 불가 → MAX 먼저 구하고 원본과 INNER JOIN 주의: 조건 만족 행만 뽑을 때는 LEFT JOIN이 아닌 INNER JOIN
4. 부서별 평균 연봉 조회
WITH T1 AS (
SELECT DEPT_ID, ROUND(AVG(SAL), 0) AS AVG_SAL
FROM HR_EMPLOYEES
GROUP BY DEPT_ID
)
SELECT H.DEPT_ID, H.DEPT_NAME_EN, AVG_SAL
FROM HR_DEPARTMENT H
LEFT JOIN T1 ON H.DEPT_ID = T1.DEPT_ID
ORDER BY AVG_SAL DESC;주의:
ROUND(AVG(SAL), 1)→ 소수점 1자리 표시 /ROUND(AVG(SAL), 0)→ 정수 반올림
5. 사원별 성과금 정보 조회
WITH T1 AS (
SELECT EMP_NO, AVG(SCORE) AS AVG_SCORE
FROM HR_GRADE
GROUP BY EMP_NO
),
T2 AS (
SELECT EMP_NO,
CASE WHEN AVG_SCORE >= 96 THEN 'S'
WHEN AVG_SCORE >= 90 THEN 'A'
WHEN AVG_SCORE >= 80 THEN 'B'
ELSE 'C' END AS GRADE
FROM T1
)
SELECT H.EMP_NO, H.EMP_NAME, T2.GRADE,
CASE WHEN GRADE = 'S' THEN SAL * 0.2
WHEN GRADE = 'A' THEN SAL * 0.15
WHEN GRADE = 'B' THEN SAL * 0.1
ELSE 0 END AS BONUS
FROM HR_EMPLOYEES H
LEFT JOIN T2 ON H.EMP_NO = T2.EMP_NO
ORDER BY H.EMP_NO;핵심 개념 정리
WHERE vs HAVING
-- WHERE: GROUP BY 이전 필터 (개별 행)
SELECT FISH_TYPE, AVG(LENGTH)
FROM FISH_INFO
WHERE LENGTH IS NOT NULL
GROUP BY FISH_TYPE;
-- HAVING: GROUP BY 이후 필터 (그룹)
SELECT FISH_TYPE, AVG(LENGTH)
FROM FISH_INFO
GROUP BY FISH_TYPE
HAVING AVG(LENGTH) >= 33; -- 집계 함수 조건 → 무조건 HAVINGCOALESCE
-- NULL을 다른 값으로 치환
COALESCE(LENGTH, 10) -- LENGTH가 NULL이면 10으로 대체
-- CASE WHEN 대비 더 간결
CASE WHEN LENGTH IS NULL THEN 10 ELSE LENGTH END -- 동일 표현
COALESCE(LENGTH, 10) -- 더 간결ROUND(숫자, N)
ROUND(3.456, 2) -- → 3.46 (소수점 2자리까지 표시)
ROUND(3.456, 0) -- → 3 (정수 반올림)
ROUND(314.5, -1) -- → 310 (십의 자리 반올림)
TRUNCATE(n, d) -- 버림
CEIL(n) -- 올림
FLOOR(n) -- 내림INNER JOIN vs LEFT JOIN 선택 기준
-- LEFT JOIN: 왼쪽 테이블 전체 유지 (없으면 NULL)
-- → 자식 수 구하기, 없어도 전체 출력해야 할 때
-- INNER JOIN: 양쪽 모두 존재하는 행만 반환
-- → 특정 조건 만족 행만 뽑을 때 (최대값 행 복원 등)틀렸던 포인트
| 실수 | 원인 | 해결 |
|---|---|---|
ELSE THEN 'HIGH' |
CASE WHEN 문법 오류 | ELSE 'HIGH' (THEN 제거) |
HAVING 대신 WHERE |
집계 후 필터링 개념 혼동 | 집계 함수 조건 → HAVING |
LEFT JOIN으로 모든 행 포함 |
JOIN 유형 선택 오류 | 조건 만족 행만 → INNER JOIN |
ROUND(..., 1) |
소수점 자릿수 N 오해 | 정수 반올림 → ROUND(..., 0) |