Search

11-4. 분석함수와 PARTITION BY

11-4-1. PARTITION BY

분석함수는 분석대상에 대해 분석을 수행한다. 분석함수의 OVER 절에 PARTITION BY와 ORDER BY, 그리고 RANGE/ROWS를 사용해 레코드별로 분석대상을 세밀하게 나눌 수 있다.
PARTITION BY를 사용해 특정 컬럼의 값에 따라 레코드별로 분석대상을 나눌 수 있다. 아래는 SUM OVER 분석함수를 사용한 SQL이다.
-- [SQL-11-4-1-a] PARTITION BY SELECT T1.ShopId ,T1.OrdNo ,T1.OrdDtm ,T1.OrdAmt ,SUM(T1.OrdAmt) OVER() SumOverOrdAmt ,SUM(T1.OrdAmt) OVER(PARTITION BY T1.ShopId) SumOverOrdAmtByShop FROM startdb.Ord T1 WHERE T1.OrdDtm >= STR_TO_DATE('20220101','%Y%m%d') AND T1.OrdDtm < STR_TO_DATE('20220110','%Y%m%d') AND T1.ShopId IN ('S195','S027') ORDER BY T1.ShopId ,T1.OrdDtm ASC; ShopId OrdNo OrdDtm OrdAmt SumOverOrdAmt SumOverOrdAmtByShop ------ ----- ------------------- -------- ------------- ------------------- S027 25441 2022-01-05 11:00:00 7500.000 28500.000 12000.000 S027 25485 2022-01-05 12:00:00 4500.000 28500.000 12000.000 S195 25285 2022-01-02 09:30:00 8000.000 28500.000 16500.000 S195 25443 2022-01-05 11:30:00 8500.000 28500.000 16500.000
SQL
복사
•
SumOverOrdAmt (전체 주문 금액)
◦
SUM(T1.OrdAmt) OVER()
◦
OVER() 절 내에 아무런 파티션 구분이 지정되지 않았기 때문에, 전체 레코드를 대상으로 주문 금액의 합계를 계산한다.
◦
모든 레코드에서 계산된 합계 값은 동일하며, 이는 전체 주문 금액의 총합을 나타낸다.
•
SumOverOrdAmtByShop (매장별 주문 금액)
◦
SUM(T1.OrdAmt) OVER(PARTITION BY T1.ShopId)
◦
OVER() 절 내에 PARTITION BY T1.ShopId가 포함되어 있어, ShopId별로 데이터를 그룹화하여 분석한다.
◦
이 구분에 따라 각 매장 ShopId가 같은 레코드들끼리 그룹화되어 그 그룹 내에서만 주문 금액의 합계가 계산된다.
◦
결과적으로 각 매장별로 주문 금액의 합계가 계산되며, 같은 ShopId를 가진 레코드들은 동일한 합계 값을 가집니다.
◦
PARTITION BY는 GROUP BY와 달리, 같은 값을 가진 레코드를 하나로 모으지 않고 각각 독립적으로 유지한다. 분석함수는 데이터의 건수를 변화시키지 않으면서, 각 레코드를 개별적으로 분석할 수 있도록 해준다는 것을
◦
GROUP BY 처럼 같은 값을 가진 레코드를 모아서 한 건으로 표현하지 않는다. 분석함수는 레코드의 건수를 변형시키지 않은 채 분석을 수행하는 특징이 있다.

11-4-2. PARTITION BY ~ ORDER BY

OVER 절에는 PARTITION BY와 ORDER BY를 동시에 사용할 수 있다. RANK OVER 분석함수에 PARTITION BY를 추가하면 파티션별로 순위를 구할 수 있다. 아래는 ShopOperTp 별로 TableQty에 따른 순위를 구하는 SQL이다. PARTITION BY를 먼저 정의하고 ORDER BY를 뒤에 정의한다.
-- [SQL-11-4-2-a] 파티션별 테이블수량 순위 구하기 SELECT T1.ShopID ,T1.ShopNm ,T1.TableQty ,T1.ShopOperTp ,RANK() OVER(ORDER BY T1.TableQty DESC) RankTableQty ,RANK() OVER(PARTITION BY T1.ShopOperTp ORDER BY T1.TableQty DESC) RankTableQtyByOperTp FROM startdb.Shop T1 WHERE T1.ShopStartYmd = '20180409' ORDER BY T1.ShopOperTp ASC, T1.TableQty DESC; ShopID ShopNm TableQty ShopOperTp RankTableQty RankTableQtyByOperTp ------ ---------------- -------- ---------- ------------ -------------------- S049 Dallas-3rd 21 DIST 1 1 S006 Philadelphia-1st 9 DIST 4 2 S048 San Diego-3rd 20 DRCT 2 1 S007 San Antonio-1st 10 FLAG 3 1 S021 New York-2nd 7 FLAG 5 2 S020 Washington-1st 6 FLAG 6 3
SQL
복사
PARTITION BY에도 여러 컬럼을 지정할 수 있다. PARTITION BY로 정의한 컬럼들이 끝나고 ORDER BY를 사용할 때는 콤마가 아닌 빈칸으로만 구분한다는 점에 주의하기 바란다.
•
PARTITION BY COL1, ORDER BY COL3: 비정상
•
PARTITION BY COL1 ORDER BY COL3: 정상
•
PARTITION BY COL1, COL2, ORDER BY COL3: 비정상
•
PARTITION BY COL1, COL2 ORDER BY COL3: 정상
아래는 ShopId, MemberId별로 순위를 구하는 SQL이다.
-- [SQL-11-4-2-b] SELECT T1.ShopId ,T1.MemberId ,T1.OrdDtm ,T1.OrdNo ,ROW_NUMBER() OVER(ORDER BY T1.OrdDtm ASC) RankOverDt ,ROW_NUMBER() OVER( PARTITION BY T1.ShopId ,T1.MemberId ORDER BY T1.OrdDtm ASC) RankOverDtShopMember FROM startdb.Ord T1 WHERE T1.OrdDtm >= STR_TO_DATE('20220101','%Y%m%d') AND T1.OrdDtm < STR_TO_DATE('20220201','%Y%m%d') AND T1.ShopId IN ('S195','S027') ORDER BY T1.ShopId ,T1.MemberId ASC; ShopId MemberId OrdDtm OrdNo RankOverDt RankOverDtShopMember ------ -------- ------------------- ----- ---------- -------------------- S027 M1295 2022-01-05 12:00:00 25485 4 1 S027 M1295 2022-01-11 12:00:00 25652 7 2 S027 M1295 2022-01-23 12:00:00 25837 10 3 S027 M1295 2022-01-29 12:00:00 26004 13 4 S027 M2293 2022-01-05 11:00:00 25441 2 1 S027 M2293 2022-01-11 11:00:00 25608 5 2 S027 M2293 2022-01-23 11:00:00 25793 8 3 S027 M2293 2022-01-29 11:00:00 25960 11 4 S195 M0207 2022-01-05 11:30:00 25443 3 1 S195 M0207 2022-01-11 11:30:00 25610 6 2 S195 M0207 2022-01-23 11:30:00 25795 9 3 S195 M0207 2022-01-29 11:30:00 25962 12 4 S195 M1210 2022-01-02 09:30:00 25285 1 1 S195 M1210 2022-01-30 09:30:00 26054 14 2
SQL
복사
이처럼 RANK 분석함수에 PARTITION BY를 적용하면 특정 그룹별 순위를 쉽게 구할 수 있다.

11-4-3. PARTITION BY 컬럼의 변형

컬럼을 변환해서 GROUP BY에 사용할 수 있는 것처럼, PARTITION BY의 컬럼도 변환해서 사용이 가능하다. 아래는 년월별로 상품별 주문수량 순위를 구해서 Top-3 까지만 출력하는 SQL이다.
-- [SQL-11-4-2-c] 주문년월별 Top-3 상품 SELECT T5.* FROM ( SELECT T4.OrdYm ,T4.ItemId ,T4.ItemNm ,T4.OrdQty ,RANK() OVER(PARTITION BY T4.OrdYm ORDER BY T4.OrdQty DESC) RankByYm FROM ( SELECT DATE_FORMAT(T1.OrdDtm,'%Y%m') OrdYm ,T3.ItemId ,MAX(T3.ItemNm) ItemNm ,SUM(T2.OrdQty) OrdQty FROM startdb.Ord T1 INNER JOIN startdb.OrdDet T2 ON (T2.OrdNo = T1.OrdNo) INNER JOIN startdb.Item T3 ON (T3.ItemID = T2.ItemId) WHERE T1.OrdDtm >= STR_TO_DATE('20230101','%Y%m%d') AND T1.OrdDtm < STR_TO_DATE('20230301','%Y%m%d') GROUP BY DATE_FORMAT(T1.OrdDtm,'%Y%m') ,T3.ItemId ) T4 ) T5 WHERE T5.RankByYm <= 3; OrdYm ItemId ItemNm OrdQty RankByYm ------ ------ ------------------ ------ -------- 202301 IAMR Iced Americano(R) 287 1 202301 ICLR Iced Cafe Latte(R) 286 2 202301 AMR Americano(R) 286 2 202302 ICLR Iced Cafe Latte(R) 299 1 202302 AMR Americano(R) 299 1 202302 IAMR Iced Americano(R) 298 3
SQL
복사

BOOSTER QUIZ

BOOSTER QUIZ ERD

BOOSTER QUIZ 11-4-1

2023년 1월 주문에서 M0200,M0201,M0202 회원의 데이터만 조회해주세요. 주문 리스트와 회원별 주문금액합계를 컬럼으로 추가해 보여주세요.
•
대상 테이블: 주문(Ord)
•
조회 조건: OrdDtm이 2023년 1월이면서 MemberId가 M0200,M0201,M0202인 데이터
•
조회 컬럼: MemberId, OrdDtm, OrdAmt, SumOverAmtMember
•
추가 조건
◦
SumOverAmtMember는 조회된 데이터에서 회원별 주문금액 합계입니다. 분석함수에 PARTITION을 적용해 구합니다.
◦
MemberId, OrdDtm으로 오름차순 정렬해주세요.
MemberId OrdDtm OrdAmt SumOverAmtMember -------- ------------------- -------- ---------------- M0200 2023-01-02 10:00:00 4500.000 12500.000 M0200 2023-01-30 10:00:00 8000.000 12500.000 M0201 2023-01-05 10:00:00 9000.000 27500.000 M0201 2023-01-11 10:00:00 9500.000 27500.000 M0201 2023-01-23 10:00:00 4500.000 27500.000 M0201 2023-01-29 10:00:00 4500.000 27500.000 M0202 2023-01-02 11:00:00 4500.000 9500.000 M0202 2023-01-30 11:00:00 5000.000 9500.000
SQL
복사

BOOSTER QUIZ 11-4-2

2023년 1월부터 2023년 3월 주문에 대해, 주문년월별로 주문금액이 가장 높은 매장 하나씩을 조회해주세요.
•
대상 테이블: 매장(Shop), 주문(Ord)
•
조회 조건: OrdDtm이 2023년 1월부터 2023년 3월까지인 주문 데이터
•
조회 컬럼: OrdYm, ShopId, ShopNm, SumOrdAmt, RankByYm
•
추가 조건
◦
단계적으로 SQL을 작성합니다.
◦
첫 번째 인라인 뷰(IV1)
▪
OrdYm은 OrdDtm을 년월형태로 변환한 값이다.
▪
ShopId별 OrdYm별 GROUP BY 처리하시오
▪
SumOrdAmt는 OrdYm, ShopId별 OrdAmt를 SUM한 값
◦
두 번째 인라인 뷰(IV2)
▪
첫 번째 인라인 뷰(IV1)를 활용해 RankByYm 구하기
▪
RankByYm은 OrdYm별로 OrdAmt에 따른 순위
•
RANK 분석함수와 PARTITION BY를 사용해 구한다.
◦
메인 쿼리
▪
두 번째 인라인 뷰(IV2)에서 RankByYm이 1인 데이터만 조회
OrdYm ShopId ShopNm SumOrdAmt RankByYm ------ ------ ------------- ---------- -------- 202301 S230 San Jose-12th 210000.000 1 202302 S244 Houston-13th 173500.000 1 202303 S134 Columbus-7th 557000.000 1
SQL
복사