SQL 튜터 세션 정리

SQL
프로그래머스
CASE WHEN, HAVING, COALESCE, MAX + INNER JOIN 패턴 등 핵심 SQL 개념 (5문제)
Published

2026.04.16

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;  -- 집계 함수 조건 → 무조건 HAVING

COALESCE

-- 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)

다음에 공부할 것