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