카테고리 없음
데이터 분석 공부 일지 4일차 250424
elya0919
2025. 4. 24. 17:58
지난 시간 배웠던 내용
문자변경
1. replace
2. substr
3. concat
조건
1. if
2. case
4-2 서브쿼리문
# 실습 1 음식 준비시간이 25분보다 초과한 시간을 가져오기
# select order_id, restaurant_name, food_preparation_time-25 over_time
# from food_orders
# 먼저 준비시간에서 -25를 하면 초과되는 시간을 알 수 있으니 먼저 쿼리를 작성해
# 서브쿼리로 만들어준다.
select order_id, restaurant_name, if(over_time>=0, over_time, 0) over_time
# 고객번호 , 식당이름, 만약 오버타임이 0 이상이면 오버타임 출력, 아니면 0 출력 을 오버타임이란 컬럼으로 만들겠다.
from
(
select order_id, restaurant_name, food_preparation_time-25 over_time
# 여기서부터 서브쿼리문 고객번호,식당이름, 음식준비시간-25을 오버타임으로 별칭으로 변경
from food_orders
# 이 쿼리문은 음식정보테이블에서 가져오고 a라는 별칭으로 변경
) a
# 음식 준비시간이 25분을 초과하는 연산을 먼저하기위해
# 서브쿼리로 연산이 되어있는 테이블을 만들어 사용해 쿼리를 보다 간단하게 만든다.
4-3 실습
* 꿀팁
= 서브쿼리문 작성 시 보고싶은 쿼리만 선택해서 실행시키면 그 쿼리의 결과만 볼 수 있다.
[실습] User Segmentation 와 조건별 수수료를 Subquery 로 결합해보기
- 1) [실습] 음식점의 평균 단가별 segmentation 을 진행하고, 그룹에 따라 수수료 연산하기
(수수료 구간 -
~5000원 미만 0.5%
~20000원 미만 1%
~30000원 미만 2%
30000원 초과 3%)
# 음식점들의 수수료를 구하니 restaurant_name
# 그리고 평균단가 * 수수료 비율을 하면 수수료
select restaurant_name, price_per_plate * ratio_of_add
FROM
(
# 2. 두 번째 서브쿼리 평균단가를 구했으니 구간별 수수료 적용 아래 쿼리 작성
select restaurant_name,
case
when price_per_plate < 5000 then 0.005
when price_per_plate between 5000 and 19999 then 0.01
when price_per_plate between 20000 and 39999 then 0.02
when price_per_plate > 30000 then 0.03
end ratio_of_add,
price_per_plate
from
(
# 1. 첫 번째 서브쿼리 평균단가를 구해야 구간별 수수료를 할 수 있으니 아래 쿼리 작성
SELECT restaurant_name, avg(price/quantity) price_per_plate
FROM food_orders
GROUP BY restaurant_name
) a
) b
# case를 활용해 그룹을 나눠줌.
# 풀다보니 between, else를 썼는데 결과 값은 강의 쿼리랑 다르지 않고 가독성도 더 좋은 것 같아서 그냥 둠
SELECT restaurant_name , a.시도, # 한글로 시도 써봄 서브쿼리를 a라고 해서 a. 해줘야함
case
when avg_time <= 20 then '<= 20'
when avg_time between 21 and 29 then'20<x<30'
else '>30' end time_segment
from
(
# 평균 배달시간을 알아야 그룹화 할 수 있으니 아래 서브쿼리 작성
select restaurant_name , substr(addr,1,2) as "시도", AVG(delivery_time) avg_time
from food_orders
group by 1,2
) a
4-4 [실습] 복잡한 연산을 Subquery 로 수행하기
- [실습] 음식 타입별 ~~지역별~~ 총 주문수량과 음식점 수를 연산하고,
주문수량과 음식점수 별 수수료율을 산정하기
(음식점수 5개 이상, 주문수 30개 이상 → 수수료 0.5%
음식점수 5개 이상, 주문수 30개 미만 → 수수료 0.8%
음식점수 5개 미만, 주문수 30개 이상 → 수수료 1%
음식점수 5개 미만, 주문수 30개 미만 → 수수로 2%)
select
a.시도,
cuisine_type,
total_quantity,
count_of_res,
# 서브쿼리에서 구한 값으로 조건에 맞게 수수료율 산정
CASE
when count_of_res >= 5 and total_quantity >= 30 then 0.005
when count_of_res >= 5 and total_quantity < 30 then 0.008
when count_of_res < 5 and total_quantity >= 30 then 0.01
when count_of_res < 5 and total_quantity < 30 then 0.02
END rate
from
(
# 총 주문수량, 음식점 수 계산을 위한 서브쿼리 먼저
select SUBSTR(addr,1,2) "시도",cuisine_type , sum(quantity) total_quantity, count(distinct restaurant_name) count_of_res
from food_orders
group by 시도, cuisine_type
) a
# 지역별로 묶기 위해서는 지역+타입별로 그룹화 필요
# 서브쿼리에서 지역을 추가해서 지역+타입을 하나로 묶으면 전체 지역+타입별로 나옴
# 이렇게 묶으면 예를 들어 경기 French의 수수료와 서울 French의 수수료가 달라짐 중요함
/*- 2) [실습] 음식점의 총 주문수량과 주문 금액을 연산하고, 주문 수량을 기반으로 수수료 할인율 구하기
(할인조건
수량이 5개 이하 → 10%
수량이 15개 초과, 총 주문금액이 300000 이상 → 0.5%
이 외에는 일괄 1%)*/
# 서브쿼리를 이용해 할인조건에 맞는 할인율 구하기
select res_name,
case
when total_quantity <= 5 then 0.1
when total_quantity > 15 and total_price > 300000 then 0.005
else 0.01
end "할인율"
from
(
# 총 주문수량, 주문금액을 구하는 서브쿼리 먼저
select
restaurant_name as res_name,
sum(quantity) as total_quantity,
sum(price) as total_price
from food_orders
group by restaurant_name
) a
# 처음에 sum(price)가 아닌 price * sum(quantity)로 했는데
# 그래도 결과는 같게 나오지만 다른 문제에서는 가격이 다르다면 값이 틀림
# 그래서 총 주문금액 구할 때 sum(price)를 해줘야함
# 추가로 case문에 0.1 대신 '10%'이렇게 적었는데 SQL에서는 나중에 연산을 할 수 있으니
# 0.1로 적는게 맞음
4-5 join
join이란 ?
join 원리
join 실습
4-6 join 실습
- 1) [실습] 한국 음식의 주문별 결제 수단과 수수료율을 조회하기
(조회 컬럼 : 주문 번호, 식당 이름, 주문 가격, 결제 수단, 수수료율)
*결제 정보가 없는 경우도 포함하여 조회
=(정보가 없는 null값을 포함하는건 left join)
select fo.order_id, fo.restaurant_name, fo.price, p.pay_type, p.vat
from food_orders fo left join payments p on fo.order_id = p.order_id
where fo.cuisine_type = 'Korean'
- 2) [실습] 고객의 주문 식당 조회하기
(조회 컬럼 : 고객 이름, 연령, 성별, 주문 식당)
*고객명으로 정렬, 중복 없도록 조회
= 정렬 -> order by, 중복x -> distinct(select절 전용 기능이다.)
select distinct c.name , c.age , c.gender, fo.restaurant_name
from customers c join food_orders fo on c.customer_id = fo.customer_id
ORDER BY c.name
4-7 [실습] JOIN으로 두 테이블의 값을 연산하기
- 1) [실습] 주문 가격과 수수료율을 곱하여 주문별 수수료 구하기
(조회 컬럼 : 주문 번호, 식당 이름, 주문 가격, 수수료율, 수수료)
*수수료율이 있는 경우만 조회
select
fo.order_id,
fo.restaurant_name,
fo.price, p.vat,
fo.price*p.vat "수수료율"
from food_orders fo join payments p on fo.order_id = p.order_id
- 2) [실습] 50세 이상 고객의 연령에 따라 경로 할인율을 적용하고, 음식 타입별로 원래 가격과 할인 적용 가격 합을 구하기
(**먼저 연산해야하는 부분이 있다면 서브쿼리 활용**)
(조회 컬럼 : 음식 타입, 원래 가격, 할인 적용 가격)
*할인 : (나이-50)*0.005
* 고객 정보가 없는 경우도 포함하여 조회, 할인 금액이 큰 순서대로 정렬
select cuisine_type "음식 타입", sum(price) "원래 가격", sum(price * discount_rate)"할인 적용 가격"
FROM
(
select fo.cuisine_type ,c.age, fo.price, (c.age-50)*0.005 as discount_rate
from customers c join food_orders fo on c.customer_id = fo.customer_id
where c.age >= 50
) a
group by cuisine_type
order by sum(price -(price * discount_rate)) desc
4주차 숙제
1. 식당별 평균 음식 주문 금액과 주문자의 평균 연령을 기반으로 Segmentation 하기
평균 음식 주문 금액 기준 : 5,000 이하 / ~10,000 / ~30,000 / 30,000 초과
평균 연령 : ~ 20대 / 30대 / 40대 / 50대 이상
두 테이블 모두에 데이터가 있는 경우만 조회(*** inner join 쓰라는 말 ***),
식당 이름 순으로 오름차순 정렬 (*** order by ***)
SQL 기본구조 적어보기
각 테이블에서 필요한 컬럼 정리하기
Join 문으로 데이터 조회문 적어보기
데이터를 연산해보기
연산한 데이터를 segmentation 에 활용하기 -> 그룹화 -> case
# 실수로 case문에 then price_group1라고 적어서 실행 안됌.
# then 'price_group1'인데 다 풀어놓고 작은 따옴표 실수..
select restaurant_name,
case when price <=5000 then 'price_group1'
when price >5000 and price <=10000 then 'price_group2'
when price >10000 and price <=30000 then 'price_group3'
when price >30000 then 'price_group4' end price_group,
case when age <30 then 'age_group1'
when age between 30 and 39 then 'age_group2'
when age between 40 and 49 then 'age_group3'
else 'age_group4' end age_group
from
(
select a.restaurant_name,
avg(price) price,
avg(age) age
from food_orders a inner join customers b on a.customer_id=b.customer_id
group by 1
) t
order by 1
* 오늘 자주 했던 실수 *
- 서브쿼리를 사용하면 from에 새롭게 내가 만든 테이블이 온다는 느낌
- 그래서 밖에 select문에서 서브쿼리에 없는 컬럼을 선택하면 안됌. 테이블에 없는 컬럼을 선택했기때문