[TIL] SQL 고인물(?)의 꼼수 쿼리, data type을 바꾸는 CAST 함수

히끼·2024년 2월 18일

TIL

목록 보기
5/43

⚠️ 읽기 전 주의사항

본인은 현업에서 3년 간 SQL을 쓰면서 SQL에 매우 익숙한 상황.
내일배움캠프에서 SQL 강의를 들으면서 이미 아는 내용이라 쿼리 길게 적기 싫다고,
수업 의도와 다른 꼼수 쿼리를 남발 중...


SQL이 처음이라면 강의 의도대로 하시길...


1. 조건을 줄 때 짧게 해보자! (Feat. CASE WHEN)

1-1. 4줄 쿼리를 1줄로 만들기

우리가 원하는 결과물
결과물1-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;

흠.. 🤔
근데 너무 길지 않나? 왜 반복되게 여러 번 적어야하지?

나의 꼼수 쿼리

select name '이름'
     , age '나이'
     , gender '성별'
	 , concat(substr(age,1,1), '0대 ', if(gender='female', '여자', '남자')) "고객 그룹"
from customers c 
where age >= 10 and age < 30;

주요 사항

  1. CASE 문으로 4줄이었던 쿼리를 CONCATIF를 사용하여 1줄로 만듦
  2. 100세 이상의 나이가 데이터에 없는 것을 확인 후, SUBSTR로 나이에서 앞자리 숫자 한개만 가져옴
  3. WHERE절에서 BETWEEN 이 아닌 비교연산 적용
    (실제 현업에서 쓸 때, 29.5와 같은 잘못된 데이터가 있을 수 있음을 많이 봐서...)

1-2. 조건을 최대한 줄여보자 (9줄 → 6줄)

우리가 원하는 결과물
결과물1-2

강의가 의도한 쿼리

select restaurant_name '식당명',
       price/quantity '단가',
       cuisine_type '음식 종류',
       order_id '주문 번호',
       case when (price/quantity <5000) and cuisine_type='Korean' then '한식1'
            when (price/quantity between 5000 and 15000) and cuisine_type='Korean' then '한식2'
            when (price/quantity > 15000) and cuisine_type='Korean' then '한식3'
            when (price/quantity <5000) and cuisine_type in ('Japanese', 'Chinese', 'Thai', 'Vietnamese', 'Indian') then '아시아식1'
            when (price/quantity between 5000 and 15000) and cuisine_type in ('Japanese', 'Chinese', 'Thai', 'Vietnamese', 'Indian') then '아시아식2'
            when (price/quantity > 15000) and cuisine_type in ('Japanese', 'Chinese', 'Thai', 'Vietnamese', 'Indian') then '아시아식3'
            when (price/quantity <5000) and cuisine_type not in ('Korean', 'Japanese', 'Chinese', 'Thai', 'Vietnamese', 'Indian') then '기타1'
            when (price/quantity between 5000 and 15000) and cuisine_type not in ('Korean', 'Japanese', 'Chinese', 'Thai', 'Vietnamese', 'Indian') then '기타2'
            when (price/quantity > 15000) and cuisine_type not in ('Korean', 'Japanese', 'Chinese', 'Thai', 'Vietnamese', 'Indian') then '기타3' end "식당 그룹"
from food_orders

강의에서 한식1, 한식2, 한식3, 아시아식1, 아시아식2, 아시아식3, 기타1, 기타2, 기타3 의 총 9개의 경우의 수를 대상으로 모두 CASE WHEN을 각각 사용했다.

한식/아시아식/기타로 분류하는 각 코드를 매번 반복하고,
그럴 때마다 IN 으로 수많은 텍스트를 치는 것이 불필요하다고 생각했음

나의 꼼수 쿼리

select restaurant_name '식당명'
	, price/quantity '단가'
	, cuisine_type '음식 종류'
	, order_id '주문 번호'
	, concat(case when cuisine_type = 'Korean' then '한식'
		          when cuisine_type in ('Japanese', 'Chinese', 'Thai', 'Vietnamese', 'Indian') then '아시아식'
		          else '기타' end
		   , case when price/quantity < 5000 then 1
		          when price/quantity <= 15000 then 2
			      else 3 end
		    ) '식당 그룹'
from food_orders

주요 사항

  1. 음식 종류(cuisine_type)별로 CASE를 나누고, '한식'과 '아시아식'이 아닌 것은 ELSE로 '기타'로 줌
  2. 단가(price/quantity)별로 조건을 줌
  3. 강의에서는 비교 연산과 BETWEEN을 혼합해서 사용해, 1그룹은 5000원 미만, 2그룹은 5000원 이상 15000원 이하, 3그룹은 15000원 초과로, 이상/이상/초과/미만이 모두 사용됨.
    실제로 코드를 볼 때 뭐가 뭔지 헷갈릴 수 있어 모두 비교연산으로 변경함

1-3. 반복을 피하자

우리가 원하는 결과물
결과물1-3

강의가 의도한 쿼리

select restaurant_name,
       order_id,
       delivery_time,
       price,
       addr,
       case when delivery_time>25 and delivery_time<=30 then price*1.05*(if(addr like '%서울%', 1.1, 1))
            when delivery_time>30 then price*1.1*(if(addr like '%서울%', 1.1, 1))
            else 0 end "수수료"
from food_orders

지역별 할증 쿼리를 두번 쓰는게 맘에 들지 않아, 반복을 줄이고자 함

나의 꼼수 쿼리

select order_id '주문번호'
	 , restaurant_name '식당'
	 , addr '주소'
	 , delivery_time '배달 시간'
	 , price '음식 가격'
	 , price * if(
	 	substr(addr, 1, 2) = '서울', 1.1, 1
	 	) * case when delivery_time > 30 then 0.1
	 			 when delivery_time > 25 then 0.05
	 			 else 0 end '배달수수료'
from food_orders 

1-4. 반복을 피하고 줄이기 (3줄 → 1줄)

우리가 원하는 결과물
결과물1-4

강의가 의도한 쿼리

select order_id '주문번호'
	 , restaurant_name '식당'
	 , day_of_the_week '주문시기'
	 , quantity '음식 수'
	 , case when day_of_the_week='Weekday' then 3000*if(quantity>3,1.2,1)
	 		when day_of_the_week='Weekend' then 3500*if(quantity>3,1.2,1)
	 		end '배달할증료'
from food_orders

day_of_the_week은 평일과 주말 두가지 경우만 있는데, 굳이 CASE를 써야할 필요가 없음
그리고 불필요하게 *if(quantity>3,1.2,1)도 두번 적은게 거슬렸음

나의 꼼수 쿼리

select order_id '주문번호'
	 , restaurant_name '식당'
	 , day_of_the_week '주문시기'
	 , quantity '음식 수'
	 , if(day_of_the_week='Weekday', 3000, 3500) * if(quantity>3,1.2,1) '배달할증료'
from food_orders

IF문 2개를 곱해줘서 간단하게 한 줄로 마무리!!



2. CAST 함수로 data type 바꾸기

# 숫자로 변경
cast(if(컬럼명='바꿀 값', 바꿀숫자, 컬럼명) as decimal)

# 문자로 변경
concat(컬럼명1, '-', cast(컬럼명2 as char))

회사에서 MySQL 을 사용해서, CAST 함수를 쓸 일은 없었지만...
언젠가 다른 SQL을 쓸 수도 있으니 알아두자.


0개의 댓글