ETC/etc3

[SQL Exercise] 5. 조건문을 이용한 카테고리 분류해보기

montmer27 2025. 11. 27. 21:15

New Skill unlocked!

조건문과 수식을 이용하여 간단한 User Segmentation 수행하기


 

1. 중요 개념

- User Segmentation

특정 조건에 부합하는 사용자들을 하나의 분류군으로 묶는 것

 

- Case when

범주별로 다른 계산이나 수식을 적용해야 할 때 사용if를 여러 개 사용한 것과 같은 효과

 


 

2. 구조

Case when(조건) then(값 또는 수식)

         when(조건) then(값 또는 수식)

         ...

         else (값 또는 수식) end

 

*else는 선택사항이나, end는 필수

 


 

3. Troubleshooting

- 목표 : 10세 이상, 30세 미만의 고객의 나이와 성별로 그룹 나누기 (이름도 같이 출력)

 

Step 1. 모범답안 보기

select name,
       age,
       gender,
       case when (age between 10 and 19) and gender='male' then "10대 남자"
            when (age between 10 and 19) and gender='female' then "10대 여자"
            when (age between 20 and 29) and gender='male' then "20대 남자"
            when (age between 20 and 29) and gender='female' then "20대 여자" end "그룹" 
from customers
where age between 10 and 29

 

Step 2. 원본 코드리뷰

select name,
       age,
       gender,
       /*where로 이미 범위가 한정돼 있는데, 20대 이상은 age>=20으로 분류하고
       20대 이하는 age<20으로 분류하면 되지 않을까?*/
       case when (age between 10 and 19) and gender='male' then "10대 남자"
            when (age between 10 and 19) and gender='female' then "10대 여자"
            when (age between 20 and 29) and gender='male' then "20대 남자"
            when (age between 20 and 29) and gender='female' then "20대 여자" end "그룹" 
from customers
where age between 10 and 29

 

Step 3. 코드 1차 최적화 시도 및 Claude에게 리뷰받기

select name,
	age,
	gender,
	case when (age>=20 and gender ='male') then '20대 남성'
		when (age>=20 and gender ='female') then '20대 여성'
		when (age>=10 and gender = 'male') then '10대 남성'
		else '10대 여성' end "그룹",
from customers
where age between 10 and 29

 

네 교수님. 이번엔 case when을 이용하여 소비자 세그먼트 컬럼을 생성한 결과 하나와, 제가 최적화한 결과를 보여드리겠습니다. 제가 최적화한 방향이 엄밀성이나 가독성 측면에서 원본 코드 대비 더 낫다고 생각하는데, 교수님께서는 어떻게 생각하는지 궁금합니다.
(원본 코드)

(내 코드)

 

Step 4. 거세게 비난받기


평가:

당신의 코드는 원본보다 훨씬 못합니다. 세 가지 심각한 문제가 있습니다.



문제 1: 논리 오류

age>=20은 20-29세뿐 아니라 30세 이상도 포함합니다. WHERE 절이 10-29세로 제한하므로 이번엔 우연히 작동하지만, WHERE 조건이 바뀌면 즉시 버그가 됩니다. age between 20 and 29가 정확합니다.

문제 2: ELSE의 무분별한 사용

ELSE '10대 여성'은 다음을 모두 10대 여성으로 분류합니다:

age=10, gender='other' age=15, gender=NULL age=19, gender='unknown'

원본은 이런 경우 NULL을 반환하여 데이터 품질 문제를 드러냅니다. 당신 코드는 잘못된 데이터를 숨깁니다.

문제 3: 가독성 저하

연령대 조건(between 20 and 29)을 반복 명시하는 것이 의도를 분명히 합니다. age>=20은 독자에게 "왜 상한이 없지?"라는 의문을 남깁니다.



결론:

최적화는 정확성을 해치지 않는 범위에서만 의미가 있습니다. 당신 코드는 조건이 4개에서 3개로 줄었지만, 엄밀성과 유지보수성을 희생했습니다.

실무에서는 원본 방식이 선호됩니다. ELSE는 "모든 정상 케이스를 명시한 후 예외 처리"에만 사용하십시오.

 


 

Step 5. What I've learned

 

1. 쿼리의 동적 변화

SQL에서는 WHERE절의 조건이 상황에 따라 동적으로 변화할 수 있다는 점을 간과했다. 모범답안에서는 WHERE절의 조건이 바뀌더라도 데이터는 항상 같은 값을 표기하겠지만, 내 코드에서는 WHERE 절의 조건이 바뀌면 조회 결과가 바뀌게 된다.

 

2. 짧은 글이라고 한눈에 들어오는 건 아니다.

코드의 길이가 짧아졌으므로 가독성이 더 높아졌다고 생각했지만 길이가 짧아진다고 반드시 가독성이 높아지는 것은 아니다.

모범답안에서는 WHERE 조건까지 읽지 않고도 20대와 10대를 성별로 나누어 4개의 세그먼트를 구현한 의도를 빠르게 파악할 수 있지만, 내 코드에서는 그 의도가 다소 불명확하다.

 

3. 필터가 촘촘하지 않으면 품질 낮은 데이터가 섞여나올 수 있다.

나는 gender 컬럼의 값이 'male'과 'female'로만 구성되어 있을 것이라고 전제했지만, 실제론 그렇지 않은 데이터도 섞여 있을 수도 있다. 쿼리문 내 조건절에서 이를 정확히 명시해주어야 'null', 'unknown'과 같은 예상치 못한 데이터가 조회되는 것을 예방할 수 있다.

 

+추가 트러블슈팅 : 아래 코드는 무엇이 틀렸을까?

설명 : 주문일자가 평일이면 배달시간이 25분 초과되면 지각이고, 주문일자가 주말이면 30분 초과되면 지각이다.

SELECT order_id,
	restaurant_name,
	day_of_the_week,
	delivery_time,
	case when day_of_the_week = 'Weekday' then if(delivery_time<25,'On-Time')
	when day_of_the_week = 'Weekend' then if(delivery_time<25,'On-Time')
	else 'Late' end '지연여부'
FROM food_orders

 

정답

더보기

문제 : if 함수에 인수를 적게 입력했다.

 

[if 함수 사용법]

if(조건, 참일 때 값(수식), 거짓일 때 값(수식))

 

코드를 올바르게 고치면 다음과 같다.

SELECT order_id,
	restaurant_name,
	day_of_the_week,
	delivery_time,
	case when day_of_the_week = 'Weekday' then if(delivery_time<25,'On-Time', 'Late')
	when day_of_the_week = 'Weekend' then if(delivery_time<25,'On-Time', 'Late') end '지연여부'
FROM food_orders

(번외) 위 Troubleshooting에 대한 Claude 교수님의 설명을 들어보자.

더보기

**문제 진단:**

CASE WHEN 내부에서 IF 함수를 **불완전하게** 사용했습니다. IF(조건, 참일 때 값, **거짓일 때 값**)은 3개 인자가 필수인데, 당신은 2개만 제공했습니다.

---

**수정 방안 2가지:**

**방안 1: IF 함수 완성**

SELECT order_id,
    restaurant_name,
    day_of_the_week,
    delivery_time,
    CASE 
        WHEN day_of_the_week = 'Weekday' THEN IF(delivery_time < 25, 'On-Time', 'Late')
        WHEN day_of_the_week = 'Weekend' THEN IF(delivery_time < 30, 'On-Time', 'Late')
        ELSE 'Late' 
    END AS '지연여부'
FROM food_orders;


**방안 2: CASE WHEN만 사용 (권장)**

SELECT order_id,
    restaurant_name,
    day_of_the_week,
    delivery_time,
    CASE 
        WHEN day_of_the_week = 'Weekday' AND delivery_time < 25 THEN 'On-Time'
        WHEN day_of_the_week = 'Weekend' AND delivery_time < 30 THEN 'On-Time'
        ELSE 'Late' 
    END AS '지연여부'
FROM food_orders;

 

 

**추가 지적:**

CASE 안에 IF를 중첩하는 것보다 **CASE WHEN에 AND 조건**을 쓰는 것이 더 명확합니다.

방안 2를 사용하십시오.