GROUP BY vs. PARTITION BY: 유사점과 차이점

Suhyeon Lee·2024년 9월 12일
0

요약

  • GROUP BY와 PARTITION BY는 데이터를 “그룹화”한다는 점은 유사
    • 유사점: GROUP BY와 PARTITION BY 모두 집계된 값을 반환할 때 사용
  • 하지만 둘 사이에는 아주 큰 차이점이 존재함
    • 차이점
    1. GROUP BY를 사용하면 기존 행들이 합쳐짐 (집계된 값을 반환하면서 원래 행에 있었던 값을 함께 볼 수 없음)
    2. PARTITION BY를 사용할 경우 집계된 값을 반환하면서 동시에 기존 행의 값들도 함께 볼 수 있음
    3. PARTITION BY는 OVER()와 윈도우 함수와 함께 사용됨

GROUP BY

  • 특정 기준으로 데이터를 정의하고자 할 때
    • 특정 기준 == 분석을 할 때 분류 기준으로 삼는 것들
      • 임직원의 정보를 ‘연봉 인상률’을 기준으로 그룹화
      • 기차 정보를 기차의 ‘출발역’ 기준으로 그룹화
      • 매출 정보를 ‘연도’ 및 ‘월별’로 그룹화
  • 기존 행에 있던 데이터는 우리가 제공한 새로운 기준에 의해 생성된 새로운 행에 입력됨
    • 집계 함수를 사용하여 기존 행에 있던 값들을 계산한 후 새로운 행에 입력해 줄 수 도 있음
      • 집계함수: COUNT, SUM, AVG, MIN, MAX, …
        → 데이터를 하나로 합쳐줌
      • 합치는 과정에서 기존의 상세 데이터들을 잃게 됨

예시

train 테이블

idmodelmax_speedproduction_yearfirst_class_placessecond_class_places
1InterCity 100160200030230
2InterCity 100160200040210
3InterCity 125200200140180
4Pendolino 390240201245150
5Pendolino ETR310240201050250
6Pendolino 390240201060250

journey 테이블

idtrain_idroute_iddate
1112016-01-03
2122016-01-04
3132016-01-05
4142016-01-06
5222016-01-03
6232016-01-04
7242016-01-05
8252016-01-06
9332016-01-03
10352016-01-04
11352016-01-05
12362016-01-06
13442016-01-04
14452016-01-04
15462016-01-05
16472016-01-06
17522016-01-03
18512016-01-05
19532016-01-05
20512016-01-06
21632016-01-03
22632016-01-04
23612016-01-05

route 테이블

idnamefrom_cityto_citydistance
1Manchester ExpressSheffieldManchester60
2GoToLeadsManchesterLeeds70
3StudentRouteLondonOxford90
4MiddleEnglandWayLondonLeicester160
5BeatlesRouteLiverpoolYork160
6NewcastleDailyYorkNewcastle135
7ScotlandSpeedNewcastleEdinburgh200
  • train 테이블과 journey 테이블을 활용해 기차와 해당 기차의 여정에 관한 정보 추출

    1. 기차의 고유 아이디를 기준으로 2개의 테이블 조인

      SELECT
       t.id,
       t.model,
       j.*
      FROM train AS t
      INNER JOIN journey AS j
           ON t.id = j.train_id
      ORDER BY t.id;

      → 실행 결과:

      Idmodelidtrain_idroute_iddate
      1InterCity 1001111/3/2016
      1InterCity 10025151/3/2016
      1InterCity 1002121/4/2016
      1InterCity 1003131/5/2016
      1InterCity 1004141/6/2016
      2InterCity 1006231/4/2016
      2InterCity 1007241/5/2016
      2InterCity 1008251/6/2016
      2InterCity 1005221/3/2016
      3InterCity 12510351/4/2016
      3InterCity 12511351/5/2016
      3InterCity 12529341/3/2016
      3InterCity 12527331/5/2016
      3InterCity 12512361/6/2016
      3InterCity 1259331/3/2016
      4Pendolino 39016471/6/2016
      4Pendolino 39013441/4/2016
      4Pendolino 39014451/4/2016
      4Pendolino 39015461/5/2016
      4Pendolino 39028461/6/2016
    2. GROUP BY를 활용해 쿼리문 작성

      SELECT
       t.id,
       t.model,
       COUNT(*) AS routes
      FROM train
      INNER JOIN journey AS j
           ON t.id = j.train_id
      GROUP BY t.id, t.model
      ORDER BY t.id

      → 실행 결과:

      idmodelroutes
      1InterCity 1005
      2InterCity 1004
      3InterCity 1256
      4Pendolino 3905
  • 결과만 보면 무엇이 달라졌는지 확실히 알 수 있음

    • 기차의 아이디와 모델명으로 데이터를 그룹지었음
    • 이 과정에서 journey 테이블에 있던 행 단위의 세세한 경로 버림
  • 집계 함수는 GROUP BY 없이도 사용할 수 있지만 대부분의 경우 집계 함수를 GROUP BY와 함께 사용함

💡 집계 함수 작동 원리
1. 동일한 값을 여러 개 갖고 있는 열의 이름을 GROUP BY 절에 적어줌으로써 데이터가 그룹 지어질 수 있는 기준으로 제공
2. 집계 함수가 동일한 값을 하나의 값으로 합치기 위해 그 행들의 값을 계산
3. 집계 함수를 통해 값을 합치는 과정에서 기존의 행들은 사라짐(집계 함수를 통해 구한 값들을 볼 수는 있어도 기존에 있던 정보를 함께 볼 수는 없음)

PARTITION BY

  • 특정 기준에 한정하여 집계된 값을 계산
  • OVER절과 윈도우 함수와 함께 사용해 여러 행의 집계된 값을 구함
    • 모든 집계 함수는 윈도우 함수로 사용할 수 있음
  • GROUP BY와는 달리 기존 행의 세세한 정보들은 사라지지 않고 그대로 유지
    • 기존의 데이터와 집계된 값을 함께 나란히 볼 수 있다
SELECT
 t.id,
 t.model,
 r.name,
 r.from_city,
 r.to_city,
 COUNT(*) OVER(PARTITION BY t.id ORDER BY t.id) AS routes,
 COUNT(*) OVER() AS routes_total
FROM train AS t
INNER JOIN journey AS j
      ON t.id = j.train_id
INNER JOIN route AS r
      ON j.route_id = r.id;

→ 실행 결과:

Idmodelnamefrom_cityto_cityroutesroutes_total
1InterCity 100Manchester ExpressSheffieldManchester530
1InterCity 100BeatlesRouteLiverpoolYork530
1InterCity 100GoToLeadsManchesterLeeds530
1InterCity 100StudentRouteLondonOxford530
1InterCity 100MiddleEnglandWayLondonLeicester530
2InterCity 100StudentRouteLondonOxford430
2InterCity 100MiddleEnglandWayLondonLeicester430
2InterCity 100BeatlesRouteLiverpoolYork430
2InterCity 100GoToLeadsManchesterLeeds430
3InterCity 125BeatlesRouteLiverpoolYork630
3InterCity 125BeatlesRouteLiverpoolYork630
3InterCity 125MiddleEnglandWayLondonLeicester630
3InterCity 125StudentRouteLondonOxford630
3InterCity 125NewcastleDailyYorkNewcastle630
3InterCity 125StudentRouteLondonOxford630
4Pendolino 390ScotlandSpeedNewcastleEdinburgh530
4Pendolino 390MiddleEnglandWayLondonLeicester530
4Pendolino 390BeatlesRouteLiverpoolYork530
4Pendolino 390NewcastleDailyYorkNewcastle530
4Pendolino 390NewcastleDailyYorkNewcastle530
5Pendolino ETR310StudentRouteLondonOxford530

PARTITION BY 핵심 포인트

  1. GROUP BY를 사용하지 않았지만 여전히 집계된 값을 구할 수 있음 (routes 열과 routes_total 열)
  2. PARTITION BY를 통해 얻어낸 결과에는 기존 데이터들이 그대로 있고 중복되는 데이터를 지우지 않았음. 그리고 집계 함수를 통해 구한 값은 모든 행마다 부여되어 있음
    • GROUP BY 를 사용한 쿼리문에서도 기차의 아이디와 모델명을 추출해 달라고 SELECT 문에 적었지만 GROUP BY는 기차의 아이디와 모델명을 기준으로 데이터를 합치느라 중복되는 기존 데이터는 다 지우고 기준이 될 수 있도록 한 개씩만 남겨놓았음
  3. COUNT(*) OVER() AS routes_total은 집계되어야 할 행들끼리 구분 짓지 않았기 때문에 (PARTITION BY를 적지 않음) 모든 행이 집계 함수의 대상이 되어 30이라는 숫자가 모든 행마다 부여된 점
  4. COUNT(*) OVER(PARTITION BY t.id) ORDER BY t.id)) AS routes 부분
    • PARTITION BY를 통해 각 기차 아이디를 기준으로 행을 집계해달라고 요청해 routes 열을 보면 각 아이디마다 서로 다른 집계값을 가지고 있는 것을 확인할 수 있음
  • 우리가 알고 있는 일반적인 집계 함수를 OVER 와 함께 윈도우 함수로 사용하면 기존 데이터를 그대로 유지한 채 새로운 집계 값을 구할 수 있음

윈도우 함수

  • 집계 함수 이외에도, 상당히 유용한 윈도우 함수들이 존재함
  • 윈도우 함수는 중첩해서 사용할 수 없음
    • 하지만 서브쿼리는 사용 가능함
  1. ROW_NUMBER 함수 : 각 행에 연속적인 숫자를 부여(괄호 안에 열 이름을 적을 수 없음)
  2. RANK 함수 : ROW_NUMBER 함수와 비슷하나, 해당 함수는 괄호 안에 열 이름을 적을 수 있음
    • 순위는 괄호 안에 적는 열의 값을 기준으로 부여
      • 만약 동일한 값을 가지고 있는 행이 여러 개 존재한다면, 그 행들은 모두 똑같은 순위를 부여받음
      • 그다음으로 부여되는 순위는 똑같은 순위를 부여받은 행의 개수만큼 뛰어넘음
      • 예를 들어 10위가 총 2개의 행에게 부여되었다면 그 다음 순위는 11이 아닌 12
  3. DENSE_RANK 함수 : RANK 함수와 거의 유사하지만 이 함수는 숫자를 뛰어넘어 순위를 부여하지 않음(10위가 총 2개의 행에게 부여되었다 하더라도 그 다음 순위로 11을 부여)
  4. NTILE 함수 : 4분위, 십분위, 백분위 등을 계산할 때 사용
  5. LAG와 LEAD 함수 : 특정 행 이전 혹은 이후의 행을 반환

profile
2 B R 0 2 B

0개의 댓글