이동준1
아웃풋 공부
이동준1
전체 방문자
오늘
어제
  • 분류 전체보기 (87) N
    • airflow (8)
    • sql (23)
    • aws (12)
    • python (3)
    • 네트워크 (12)
    • 알고리즘 (2)
    • 짧은서평 (27) N

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 고통의비밀
  • 고통의 비밀
  • AWS
  • Network
  • 통증해방
  • 네트워크
  • 마음의기술
  • regexp
  • 퓨처셀프
  • 통증해방 서평
  • 유연함의힘
  • 마음의기술 서평
  • 서평

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
이동준1

아웃풋 공부

sql

[sql] 테이블 관계를 고려한 aggregation

2023. 12. 31. 01:07

https://indistract.tistory.com/58

 

[sql] 월 전체 매출액 대비 비율

아래 4가지 테이블을 이용해서 월별 상품 카테고리별 구매건수와 매출을 구한뒤, 월별로 각 카테고리가 얼만큼의 매출 비중을 차지하는지 구해보려한다. ① nw.order: 주문정보 테이블 ② nw.order_it

indistract.tistory.com

 

앞선 게시글에서는 월내 카테고리별 매출액 대비 비율을 구해봤다. 이번에는 비슷하게 카테고리내 상품별 매출액 대비 비율을 구하며, 추가적으로 각 카테고리내 상품의 매출액 순위가지 구해보려한다.

 

각 행의 순위를 구하려면 row_number() 함수를 사용해주면된다. 그리고 어떤 기준으로 partiton하고, 어떤 기준으로 순위를 매길것인지에 대한 정보는 over(partition by ① 구분 기준 order by ② 순위 기준) 으로 작성해주면 되겠다.

 

우리는 ①각 카테고리마다 ②각 상품의 매출 순위를 구하고싶으므로, row_number() over(partitionby  ① 카테고리명 order by ② 매출액 desc) 라고 작성해주면된다. 끝단에 desc를 쓴 이유는 매출액이 큰 순으로 정렬하여 순위를 부여할 것이기 때문이다.

 

이를 이용해서 작성한 쿼리는 아래와 같다. 위 게시글과 쿼리 구조는 비슷하며, row_number() 함수로 순위구하는 부분만 추가된 정도이다.

with tmp as(
	select c.category_name, p.product_name, 
		count(distinct oi.order_id) as ord_cnt,
		sum(amount) as sum_amount
	from nw.order_items oi
		left join nw.products p on oi.product_id = p.product_id 
		left join nw.categories c on p.category_id = c.category_id
	group by 1, 2
)

select *,
	sum(sum_amount) over(partition by category_name) as ctg_tot_amount,
	round(sum_amount / sum(sum_amount) over(partition by category_name), 3) as ratio,
	row_number() over(partition by category_name order by sum_amount desc) as rank_amount
from tmp
order by category_name, sum_amount desc
;

 

위 쿼리는 테이블 관계를 고려한다면 조금 다르게 작성할수 있다. 카테고리 정보와 상품 정보를 얻기 위해서 각각 nw.categories 테이블과 nw,products  테이블을 사용했는데, 이 두 테이블은 1:M 관계를 가진다. 즉, 하나의 카테고리가 여러 개의 상품명에 연결될 수 있다. 예를들어, '전자제품' 이란 카테고리는 '컴퓨터', '태블릿', 그리고 '키보드' 라는 상품에 연결될수 있다. 반대로 하나의 상품은 하나의 카테고리만 연결되는 구조이다.

 

위 쿼리에서는 임시 테이블(tmp)를 생성할때 group by 기준을 c.category_name과 p.product_name 칼럼 2가지로 설정했지만, 이 테이블 관계를 이용한다면 p.product_name만 group by 기준으로 잡고 c.category_name은 집계하여 max(c.category_name)으로 집계하여도 무방하다. 하나의 상품은 하나의 카테고리만을 가지기 때문이다. 

 

이런 테이블 관계 특징을 고려해서 수정한 쿼리는 아래와 같다.

with tmp as(
	select  
		p.product_name,
		max(c.category_name) as category_name,
		count(distinct oi.order_id) as ord_cnt,
		sum(amount) as sum_amount
	from nw.order_items oi
		left join nw.products p on oi.product_id = p.product_id 
		left join nw.categories c on p.category_id = c.category_id
	group by 1
)

select *,
	sum(sum_amount) over(partition by category_name) as ctg_tot_amount,
	round(sum_amount / sum(sum_amount) over(partition by category_name), 3) as ratio,
	row_number() over(partition by category_name order by sum_amount desc) as rn
from tmp
order by category_name, sum_amount desc
;

'sql' 카테고리의 다른 글

[sql] 가중 이동평균  (0) 2024.01.05
[sql] 이동평균  (2) 2024.01.01
[sql] 월 전체 매출액 대비 비율  (0) 2023.12.29
[sql] date_trunc  (0) 2023.12.28
[SQL] Aggregation Without Grouping  (0) 2023.01.04
    'sql' 카테고리의 다른 글
    • [sql] 가중 이동평균
    • [sql] 이동평균
    • [sql] 월 전체 매출액 대비 비율
    • [sql] date_trunc
    이동준1
    이동준1

    티스토리툴바