Back to til
Jul 23, 2025
3 min read

TIL SQL 학습 정리 2

지난 며칠 동안 SQL 문제풀이를 하면서 학습한 내용들을 정리했습니다.

1. WHERE vs. HAVING

둘 다 필터링을 하지만, 적용되는 시점이 다릅니다.

  • WHERE: 그룹화 전(Before), 개별 행을 필터링합니다.
  • HAVING: 그룹화 후(After), SUM(), COUNT() 등 집계 함수의 결과로 만들어진 그룹을 필터링합니다. 그리고, MySQL에서는 Having을 전체 결과를 하나의 그룹으로 간주하여 단독으로 사용할 수도 있습니다.

2. 동적으로 그룹을 만들기

가격을 10,000원 단위로 묶는 등, 정해진 구간별로 그룹화할 때 유용한 방법을 학습했습니다. 최대값을 미리 알기 어려운 경우 사용할 수 있습니다.

  • 가격대별 상품 수 구하기: FLOOR (버림) 함수를 이용해 가격대를 동적으로 생성하고 그룹화합니다.

    SELECT
        FLOOR(PRICE / 10000) * 10000 AS PRICE_GROUP,
        COUNT(PRODUCT_ID) AS PRODUCTS
    FROM PRODUCT
    GROUP BY PRICE_GROUP
    ORDER BY PRICE_GROUP ASC;
    
    1. FLOOR(PRICE / 10000):
      • 모든 상품의 PRICE를 10,000으로 나눕니다. (예: 25000 -> 2.5, 9500 -> 0.95)
      • FLOOR() 함수로 소수점 이하를 버립니다. (예: 2.5 -> 2, 0.95 -> 0)
    2. ... * 10000:
      • 버림 처리된 값에 다시 10,000을 곱해 각 가격대의 시작점(가격 그룹)을 만듭니다. (예: 2 -> 20000, 0 -> 0)
      • 이 PRICE_GROUP은 최대 가격에 상관없이 모든 가격에 대해 동적으로 생성됩니다.
    3. GROUP BY PRICE_GROUP:
      • 동일한 PRICE_GROUP 값을 가진 상품들을 하나의 그룹으로 묶습니다.
    4. COUNT(PRODUCT_ID):
      • 그룹별로 묶인 상품의 개수를 셉니다.
  • MySQL에서 GROUP BY 절에서 SELECT에서 정의한 별칭 사용이 가능한 이유

    • 보통 다음과 같이 SQL은 실행 순서를 가집니다.
      • FROM → WHERE → GROUP BY → HAVING → SELECT → DISTINCT → ORDER BY → LIMIT
    • 따라서 SELECT보다 먼저 실행되는 GROUP BY에서는 별칭을 사용할 수 없어야 합니다. 그러나, MySQL에서는 GROUP BY를 실행하기 위해 내부적으로 SELECT에 정의된 별칭과 관련된 부분을 먼저 참조하여 계산합니다. 따라서 SELECT에서 정의한 별칭을 사용할 수 있습니다. 모든 데이터베이스 벤더에서 지원하는 것은 아닙니다.
    • HAVING 에서도 사용할 수 있으며 WHERE에서는 사용할 수 없습니다.

3. IN 연산자 vs OR 반복

컬럼의 값이 목록에 있는 정확한 값과 일치하는지 확인하는 경우에는 여러 OR 조건보다 IN (...)을 사용하는 것이 가독성과 성능 모두에서 유리합니다.

SELECT
    ANIMAL_ID,
    NAME,
    SEX_UPON_INTAKE
FROM 
    ANIMAL_INS
WHERE 
    NAME IN ('Lucy', 'Ella', 'Pickle', 'Rogan', 'Sabrina', 'Mitty')
ORDER BY 
    ANIMAL_ID ASC;

4. CASE 문 단순화

CASE는 순서대로 평가되므로, NULL을 먼저 처리하거나 ELSE를 활용해 불필요한 조건을 줄일 수 있습니다.

  • 개선 전: 조건이 중복될 수 있음
CASE
    WHEN OUT_DATE <= '2022-05-01' THEN '출고완료'
    WHEN OUT_DATE > '2022-05-01' THEN '출고대기'
    ELSE '출고미정'
END
  • 개선 후: NULL을 먼저 처리하고, 순차 평가를 이용해 마지막 조건을 ELSE로 단순화
CASE
    WHEN OUT_DATE IS NULL THEN '출고미정'
    WHEN OUT_DATE <= '2022-05-01' THEN '출고완료'
    ELSE '출고대기'
END