주(state)별 침투율을 확인하고, 침투율이 특히 낮은 지역을 중심으로 침투율을 개선해보려고 합니다. 이를 위해 주별 주문수와 고객수를 뽑아주세요.
/* 주(state)별 주문수와 고객수 추출 */
-- 고객 정보 기준
-- 주문 상태는 필터링하지 않음
SELECT
customer_state,
COUNT(DISTINCT order_id) ord_cnt, -- 주문수
COUNT(DISTINCT customer_unique_id) cust_cnt -- 고객수
FROM `olist.olist_orders` ord
LEFT JOIN `olist.olist_customers` cust
ON ord.customer_id = cust.customer_id
GROUP BY customer_state
ORDER BY cust_cnt DESC
;
서브쿼리를 이용한 join을 연습해봅시다!
SELECT
cust.customer_state,
COUNT(DISTINCT ord.order_id) AS ord_cnt
FROM `olist.olist_orders` AS ord
LEFT JOIN (SELECT
customer_id,
customer_state,
customer_unique_id
FROM `olist.olist_customers` cust
WHERE customer_state IN ('SP', 'RJ')) AS cust
ON ord.customer_id = cust.customer_id
WHERE customer_state IS NOT NULL
GROUP BY 1
;
임시테이블로 만들고 사용해도 동일한 결과
서브쿼리 안에 where 절로 인해서 SP 와 RJ 주에 해당하지 않은 경우는 NULL 값을 표시
2가지 주에 해당하는 값들만 가져오기 위해 NULL은 빼고 불러오는 where절 작성
조건1. 고객수 기준 순위도 붙여주세요
조건2.전체 순위, 주(state) 내에서의 순위 둘 다 보고 싶어요
조건3.배송완료(delivered)된 건만 집계해주세요
/*
시별 주문수, 매출, 고객수 구하기
조건 1. 2017년
조건 2. 고객수 내림차순 기준 순위 제공
조건 3. 순위는 전체순위, 주(STATE)기준 순위 둘다 제공할 것
조건 4. 배송완료(order_status = 'delivered')된 건만 집계
*/
WITH tb AS (
SELECT
item.order_id,
SUM(item.price) AS ord_amt
FROM `olist.olist_order_items` AS item
GROUP BY item.order_id
) -- 매출을 가져오기 (order_id로 집계하여 중복 방지)
, base AS (
SELECT
cust.customer_state,
cust.customer_city,
COUNT(DISTINCT ord.order_id) AS ord_cnt,
COUNT(DISTINCT cust.customer_unique_id) AS cust_cnt,
SUM(tb.ord_amt) AS sum_amt,
FROM `olist.olist_orders` AS ord
LEFT JOIN `olist.olist_customers` AS cust
ON ord.customer_id = cust.customer_id
INNER JOIN tb
ON ord.order_id = tb.order_id
WHERE 1=1 -- 의미 없음. 조건을 주석처리할 때 용이
AND EXTRACT(YEAR FROM order_approved_at) = 2017
AND order_status = 'delivered'
GROUP BY 1, 2
)
SELECT
*,
RANK() OVER (ORDER BY cust_cnt DESC ) AS cust_rank, -- 전체 순위
RANK() OVER (PARTITION BY customer_state ORDER BY cust_cnt DESC ) AS state_cust_rank -- 주(State)별 순위
FROM base
ORDER BY cust_rank
;
/*
1. 월별 지표
2. +) SAFE_DIVIDE 사용 (일반 나눗셈 연산 : /)
매출 / 고객수
*/
SELECT
DATE_TRUNC(DATE(ord.order_approved_at), MONTH) AS ord_month,
SUM(item.price) AS ord_amt,
COUNT(DISTINCT customer_unique_id) AS cust_cnt,
SAFE_DIVIDE(SUM(item.price), COUNT(DISTINCT customer_unique_id)) AS avg_amt
FROM `olist.olist_orders` ord
INNER JOIN `olist.olist_order_items` item
ON ord.order_id = item.order_id
LEFT JOIN `olist.olist_customers` cust
ON ord.customer_id = cust.customer_id
GROUP BY 1
ORDER BY ord_month
;
조건)
월 – 고객uniqueID – 해당월의구매금액 – 그룹 순서
300 BRL 이상은 A, 150 BRL 이상 300 BRL 미만은 B, 그 외 C
SELECT
DATE_TRUNC(DATE(ord.order_approved_at), MONTH) AS ord_month,
customer_unique_id,
SUM(price) AS ord_amt,
CASE
WHEN SUM(price) >= 300 THEN 'A'
WHEN SUM(price) >= 150 AND SUM(price) < 300 THEN 'B'
ELSE 'C'
END AS level
FROM `olist.olist_orders` AS ord
INNER JOIN `olist.olist_order_items` AS item
ON ord.order_id = item.order_id
LEFT JOIN `olist.olist_customers` AS cust
ON ord.customer_id = cust.customer_id
WHERE 1=1
AND order_approved_at IS NOT NULL
GROUP BY 1, 2
ORDER BY ord_month, ord_amt DESC
;