0. 서브쿼리(Subquery) 어렵지 않아요! (?ㅎ)
내가 SQL을 처음 접하고,
나름 재미있게(?) 공부하다가 맞닥뜨린 첫 고비가 바로 서브쿼리였다.
SELECT절 / WHERE절 / FROM절 등 다양한 위치에서 서브쿼리를 사용할 수 있다고 배웠는데
도대체 언제 SELECT절에 서브쿼리를 쓰는지, 언제 FROM절에 서브쿼리를 쓰는지 감이 안와서 힘이 들었던 기억이 있다.
이건 당시 내가 정리했던 SQL 서브쿼리 정리노트다.
(혹시 이 게시물보다 조금 더 자세한 설명이 필요하다면, 아래 게시글 참고 요망)
[참고 게시글]
[IT 교육/SQL] - SQL 4주차 강의 노트정리[국비지원_스파르타 코딩클럽]
그런데 당시에 서브쿼리를 도대체 어디에 써야 하는가를 고민했던 것은
SQL이 조금 익숙해진 지금에 와서 보니 그렇게 중요한 것은 아니었다.
서브쿼리가 필요한 경우는,
① 해결해야 할 문제를 보니 내가 여러 번의 연산을 수행해야 된다.
② 그런데 이전의 연산 결과를 다음 연산에 이용해야 한다.
이럴 때이다.
서브쿼리의 결과를 단순히 조회하고 싶으면 SELECT문에 적고,
서브쿼리의 결과를 조건문의 조건식 중 하나로 넣고 싶으면 WEHRE절에 넣고,
서브쿼리의 결과를 하나의 테이블로 간주해 다시 거기서 조건에 따른 결과를 조회해 보고 싶으면 FROM절에 넣으면 된다.
필요하다면 이 결과를 다시 서브쿼리로 SELECT절, WHERE절, FROM절에 넣어 사용할 수 있다.
그럼 서브쿼리에 대해 실습문제 쿼리문을 보며 다시 자세히 알아보자.
1. 서브쿼리(Subquery) 집중 탐구
1-1) 서브쿼리(Subquery)
▶ 서브쿼리문의 기본 구조
- FROM절 서브쿼리
SELECT column1, special_column
FROM
( /* subquery */
SELECT column1, column2 special_column
FROM table1
) a
- WEHRE절 서브쿼리
SELECT column1, column2
FROM table1
WHERE column1 = (SELECT col1 FROM table2)
1-2) 서브쿼리(Subquery) 실습문제
문제1) 음식 주문 시간이 25분보다 초과한 시간 가져오기
: food_preparation_time(음식 주문 시간)이 25분보다 초과한 시간을 구하고 over_time이라고 이름 붙여줌
: 이 결과를 FROM절의 서브쿼리로 넣어줌
: 이 FROM절 결과를 이용해서, IF문으로 음식 주문 시간이 25분을 초과하지 않은 값들은 0으로 간주한 뒤 조회함
SELECT order_id,
restaurant_name,
IF(over_time > 0, over_time, 0) over_time
FROM
(
SELECT order_id, restaurant_name, (food_preparation_time-25) over_time
FROM food_orders
) a
▶ CASE문으로도 풀 수 있음
(모든 문제를 서브쿼리로 풀 필요는 없음. 간단하게 풀 수 있는 문제는 간단하게 풀기!)
SELECT order_id ,
restaurant_name ,
food_preparation_time ,
CASE WHEN food_preparation_time <= 25 THEN 0
WHEN food_preparation_time > 25 THEN food_preparation_time - 25
END over_time
FROM food_orders fo
▶ 조건문과 Subquery를 결합하여 User Segmentation과 연산 해보기
문제2) 음식점의 평균 단가별 segmentaion을 진행하고, 그룹에 따라 수수료 연산하기
ⓛ 첫 번째 과정_ 음식점 별 평균 음식단가 구하기
: 일단 restaurant_name(음식점 명) 별로 평균 unit_cost(음식 단가)를 구함
SELECT order_id ,
restaurant_name ,
AVG(price/quantity) unit_cost
FROM food_orders fo
Group By restaurant_name
②두 번째 과정_평균 음식 단가로 수수료 segmentation 하기
: 첫 번째 과정의 결과를 FROM절의 서브쿼리로 넣어줌.
: 그 뒤 평균 unit_cost(음식 단가) 별 vat(수수료)를 산정해 줌.
SELECT order_id,
restaurant_name,
unit_cost,
CASE WHEN unit_cost < 5000 THEN '0.5%'
WHEN unit_cost < 20000 THEN '1%'
WHEN unit_cost < 30000 THEN '2%'
ELSE '3%'
END vat
FROM
(SELECT order_id ,
restaurant_name ,
AVG(price/quantity) unit_cost
FROM food_orders fo
Group By restaurant_name) a
③ 최종_ 수수료가 적용된 평균 음식 단가 구하기(평균 음식단가 * 수수료)
: 두 번째 과정의 결과를 다시 FROM절의 서브쿼리로 넣어줌.
: 그 후 수수료가 적용된 평균 음식 단가를 마지막으로 조회해줌.
SELECT order_id,
restaurant_name,
unit_cost * vat apply_vat_price
FROM
(SELECT order_id,
restaurant_name,
unit_cost,
CASE WHEN unit_cost < 5000 THEN '0.5%'
WHEN unit_cost < 20000 THEN '1%'
WHEN unit_cost < 30000 THEN '2%'
ELSE '3%'
END vat
FROM
(SELECT order_id ,
restaurant_name ,
AVG(price/quantity) unit_cost
FROM food_orders fo
Group By restaurant_name) a) b
심화1) 음식점의 총 주문 수량과 총 주문금액을 계산하고, 주문 수량을 기반으로 수수료 할인율 구하기
- 총 주문 수량 5개 이하: 0.5% 할인
- 총 주문 수량 15개 초과, 총 주문 금액 300,000원 이상: 10% 할인
- 그 외: 일괄 1%
SELECT restaurant_name,
CASE WHEN total_quantity <= 5 then 0.005
WHEN total_quantity > 15 AND total_price >= 300000 THEN 0.1
ELSE 0.01
END vat_discount
FROM
(SELECT restaurant_name,
sum(quantity) total_quantity,
sum(price) total_price
FROM food_orders fo
Group By 1) a
서브쿼리 문제를 잘 푸는 방법은
문제를 천천히 뜯어보면서 먼저 문제를 세분화 해보고,
세분화한 문제 중 먼저 풀어야 할 문제를 골라 연산한 뒤 조회해주고,
그 연산 결과를 다음 풀어야 할 문제의 쿼리문에 서브쿼리로 넣어주는 걸 반복하면 됩니다.
별로 안 어렵쥬..? (아마..도요.?)
'데이터분석 과정 > SQL' 카테고리의 다른 글
SQL | Pivot Table 만들기 | 실습 문제 (1) | 2024.01.08 |
---|---|
SQL | JOIN(조인)할 때 ON절의 컬럼명, 꼭 같아야 할까 (0) | 2024.01.08 |
SQL | IF문, CASE문으로 범주 별 다른 조건 적용하기 (1) | 2024.01.08 |
SQL | REPLACE / SUBSTR / SUBSTRING_INDEX / CONCAT 함수 정리 + 실습 문제 (1) | 2024.01.07 |
SQL | 윈도우 함수(Window Function) 사용법 정리 | RANK함수, SUM함수 (1) | 2024.01.07 |
댓글