본문 바로가기
백엔드/SQL

SQL을 활용한 데이터 집계와 분석(1)

by dustnn 2025. 5. 24.
OLAP(Online Analytical Processing)

 

OLAP이란

 

대용량 데이터를 다양한 차원의 관점에서 빠르게 분석 및 집계(요약)하기 위한 온라인 분석 처리 기법

- 시간, 지역, 제품, 고객 등 다양한 속성별 관점에서 데이터 탐색 가능

- 경영진, 분석가들이 의사결정을 위한 통찰을 얻기 쉬움

- 의사결정을 위한 보고서 작성에 도움을 줄 수 있는 세부 분석 기법들로 구성

 

주로 의사결정 지원 시스템 또는 데이터 웨어하우스에서 사용되는 분석 기법

-> OLAP 전용 엔진 및 이를 지원하는 전용 쿼리 언어 활용

 

일반적인 관계형 데이터베이스에서도 다양한 관점의 분석 및 요약을 위해 사용 가능

-> SQL에서 확장 지원하는 구문 활용

주로, 기업용 RDBMS에서만 지원되기 때문에 MySQL Community 등 무료 RDBMS에서 미지원되는 구문은 SQL로 직접 구현 가능하다.

 

<"차원"이란?>

OLAP의 목표: 범주형 속성(차원)을 기준으로 측정값 속성을 분석하는 것

 

<종류>

분류 윈도우 함수 기반 OLAP 다차원 분석 기반 OLAP
분석 기준  행 단위
(하나의 행이 다른 행들과의 관계 속에서 갖는 의미)
컬럼 단위
(범주형 값을 갖는 컬럼들의 조합 기준으로 집계)
목적 시간 또는 특정 순서에 따른 누적 집계 및 순위 분석
(행끼리 비교)
범주형 속성 값 기준의 집계
응용 시계열 분석, 사용자 행동 분석 통계 요약, 보고서 작성에 필요한 집계 결과 생성
지원 RDBMS  - 무료 및 유료 버전의 RDBMS 모두에서 지원
- MySQL Community 8.0 이상, MySQL Enterprise 8.0 이상, Oracle 등
- MySQL Community 8.0은 일부(ROLLUP)만
지원  나머지는 직접 구현해야 함
- MySQL Enterprise 8.0 이상은 모두 지원
- Oracle은 XE(무료 버전)와 유료 버전 모두 지원
사용법 OVER() 함수와 집계 또는 순위 함수를 함께 사용
- OVER(): 집계 대상 윈도우 정의
- 집계 함수: SUM, AVG, MIN, MAX 등
- 순위 함수: RANK, DENSE_RANK 등
- GROUP BY 절과 전용 분석 연산 구문을 함께 사용
- 미지원 구문은 직접 구현 (UNION ALL, CASE 활용)
대표적인 연산 - OVER을 통해 정의된 윈도우 단위의 누적 집계
(SUM, AVG, MIN, MAX, 각종 통계 함수 적용 가능)
- OVER을 통해 정의된 윈도우 단위의 순위 계산
(RANK, DENSE_RANK, ROW_NUMBER)
- ROLL UP
- CUBE
- GROUPING SETS
- PIVOT

 

윈도우 함수 기반 OLAP

 

: 매 행에 대해 정의

over()이 있으면 "윈도우 함수 기반이구나!" 라고 생각하면 됨

쿼리 종류 정리

select 조회가 필요한 컬럼들,
	[집계함수 | 순위함수] over ([order by 측정값 속성] 또는  //윈도우 분석 대상 정의(필수/세 개 중 하나 택)
    				[partition by 범주형 속성] 또는 
                            [partition by 범주형 속성 order by 측정값 속성]
                            [rows between num1 preceding  // 윈도우 크기 정의(선택)
                            and num2 following] 선택적 추가) as 윈도잉_결과 //'윈도잉_결과': 결과 컬럼
from 집계대상테이블;

 

동작 과정

 

"over 안쪽에 윈도우 분석 대상 정의에 따라 윈도우(행 묶음) 정의

-> 그 윈도우에 대해 집계/순위함수 적용

-> 결과를 결과 컬럼(윈도잉_결과)에 넣어줌"

 

1행: 윈도우 대상 정의로 빨간색에 들어있는 2개의 행 선택 -> 집계작업(ex. sum) -> 1행 윈도잉_결과에 salary의 합 들어감

2행: 파란색에 들어있는 3개의 행 선택 -> 집계작업(ex. sum) -> 2행 윈도잉_결과에 salary의 합 들어감

8행: 노란색에 들어있는 3개의 행 선택 -> 집계작업(ex. sum) -> 8행 윈도잉_결과에 salary의 합 들어감

10행: 초록색에 들어있는 3개의 행 선택 -> 집계작업(ex. sum) -> 10행 윈도잉_결과에 salary의 합 들어감

 

<예제1>: 분석대상 order by만 / 윈도우 크기 x

 

over 뒤에 윈도우 분석 대상 -> 집계함수 -> 결과 컬럼(SUM_1, RANK_1, DRANK_1, RNUM_1)에 집계 결과 적어줌

 

1. 집계함수

sum(salary) order (order by salary) as SUM_1

 

(1) 1번째 행

- order by: salary 컬럼이 오름차순으로 정렬된 상태

* 현재 행과 동순위인 행(salary값이 같은 행)이 윈도우 없음 -> 선택된 행만 윈도우

- sum 함수 실행

* 윈도우가 한 행뿐이므로 그냥 40000 적어줌

 

(2) 2번째 행

- order by: salary 컬럼이 오름차순으로 정렬된 상태

* 현재 행과 동순위인 행(salary값이 같은 행)이 윈도우: 3번째 행

-> 윈도우: 1,2,3번째 행

- sum 함수 실행

* 윈도우 행들 salary 합 -> 40000+62000+62000=164000 적어줌

 

(3) 3번째 행

- order by: salary 컬럼이 오름차순으로 정렬된 상태

* 현재 행과 동순위인 행(salary값이 같은 행)이 윈도우: 2번째 행

-> 윈도우: 1,2,3번째 행

- sum 함수 실행

* 윈도우 행들 salary 합 -> 40000+62000+62000=164000 적어줌

 

(4) 4번째 행

- order by: salary 컬럼이 오름차순으로 정렬된 상태

* 현재 행과 동순위인 행(salary값이 같은 행)이 윈도우: 5번째 행

-> 윈도우: 1,2,3,4,5번째 행

- sum 함수 실행

* 윈도우 행들 salary 합 -> 40000+62000+62000+65000+65000=294000 적어줌

 

(5) 5번째 행

- order by: salary 컬럼이 오름차순으로 정렬된 상태

* 현재 행과 동순위인 행(salary값이 같은 행)이 윈도우: 4번째 행

-> 윈도우: 1,2,3,4,5번째 행

- sum 함수 실행

* 윈도우 행들 salary 합 -> 40000+62000+62000+65000+65000=294000 적어줌

 

6번째~끝 행도 동일한 방법으로..

집계 결과행

 

2. 순위함수

 

<rank(): 절대 순위>

rank() over (order by salary) as RANK_1

 

(1) 1번째 행

- order by: salary 컬럼이 오름차순으로 정렬된 상태

* 현재 행과 동순위인 행(salary값이 같은 행)이 윈도우 없음 -> 선택된 행만 윈도우

- rank 함수 실행: 1순위이므로 1

 

(2) 2번째 행

- order by: salary 컬럼이 오름차순으로 정렬된 상태

* 현재 행과 동순위인 행(salary값이 같은 행)이 윈도우: 3번째 행

-> 윈도우: 1,2,3번째 행

- rank 함수 실행: 2순위이므로 2

 

(3) 3번째 행

- order by: salary 컬럼이 오름차순으로 정렬된 상태

* 현재 행과 동순위인 행(salary값이 같은 행)이 윈도우: 2번째 행

-> 윈도우: 1,2,3번째 행

- rank 함수 실행: 2번째 행과 순위 같으므로 2

 

(4) 4번째 행

- order by: salary 컬럼이 오름차순으로 정렬된 상태

* 현재 행과 동순위인 행(salary값이 같은 행)이 윈도우: 5번째 행

-> 윈도우: 1,2,3,4,5번째 행

- rank 함수 실행: 순위 4이므로 4

 

(5) 5번째 행

- order by: salary 컬럼이 오름차순으로 정렬된 상태

* 현재 행과 동순위인 행(salary값이 같은 행)이 윈도우: 4번째 행

-> 윈도우: 1,2,3,4,5번째 행

- rank 함수 실행: 4번째 행과 순위 같으므로 4

 

6번째~끝 행도 동일한 방법으로..

 

 

 

 

<dense_rank(): 상대 순위>

dense_rank() over (order by salary) as DRANK_1

 

rank와 같이 순위함수이지만, 중간에 없는 숫자가 없어야 함

 

<row_number(): 윈도우 결과 함수 내 행 번호>

row_number() over (order by salary) as RNUM_1

 

 

<예제2>: 분석 대상 order by만 / 윈도우 크기 명시

 

윈도우 크기 명시 -> 동순위 고려하지 않고 크기만 고려

 

<예제3>: 분석 대상 partition by만 / 윈도우 크기 명시 x

 

partition by: 각 행에 대한 윈도우

* partition by만 있다면 윈도우 하나 내 모든 행은 동일한 순위

* partition by+order by 모두 있다면 같은 분석대상 내 행들 순위 매겨짐

ex. 1번째 행에 대한 윈도우는 그 행과 dept_name이 같은 소그룹 전체

 

 

<sum(): 합>

같은 윈도우 내에서는 모두 같음

 

<rank(): 절대 순위>

같은 윈도우 내에서는 모두 같음

-> 그냥 다 1이 됨

 

<dense_rank(): 상대 순위>

같은 윈도우 내에서는 모두 같음

-> 그냥 다 1이 됨

 

<row_number(): 윈도우 결과 함수 내 행 번호>

같은 윈도우 내에서만 순서 매김

 

<예제4>: 분석 대상 partition by만 / 윈도우 크기 명시

 

윈도우 크기가 정해지더라도 partition by 범위 넘어갈 수 없음

 

 

<sum()>

sum(salary) over (partition by dept_name
	    rows between 1 preceding
            and 1 following) as SUM_4

 

(1) 1번째 행

- partition by: dept_name별로 소그룹 분류해둠

* "dept_name=Comp.Sci."인 행들 소그룹 -> 이제 함수들 실행할 윈도우 이 범위 넘어갈 수 없음

- "rows between 1 preceding and 1 following" -> 윈도우 크기는 위 아래 행 하나씩

=> sum()은 윈도우 기준으로, rank()/dense_rank()/row_number()은 분석대상 기준으로

- sum() 함수 실행: 65000+65000=130000

 

(2) 2번째 행

- partition by: dept_name별로 소그룹 분류해둠

* "dept_name=Comp.Sci."인 행들 소그룹 -> 이제 함수들 실행할 윈도우 이 범위 넘어갈 수 없음

- "rows between 1 preceding and 1 following" -> 윈도우 크기는 위 아래 행 하나씩

=> sum()은 윈도우 기준으로, rank()/dense_rank()/row_number()은 분석대상 기준으로

- sum() 함수 실행: 65000+65000+75000=205000

 

(3) 3번째 행

- partition by: dept_name별로 소그룹 분류해둠

* "dept_name=Comp.Sci."인 행들 소그룹 -> 이제 함수들 실행할 윈도우 이 범위 넘어갈 수 없음

- "rows between 1 preceding and 1 following" -> 윈도우 크기는 위 아래 행 하나씩

=> sum()은 윈도우 기준으로, rank()/dense_rank()/row_number()은 분석대상 기준으로

- sum() 함수 실행: 65000+75000+62000=202000

 

(4) 4번째 행

- partition by: dept_name별로 소그룹 분류해둠

* "dept_name=Comp.Sci."인 행들 소그룹 -> 이제 함수들 실행할 윈도우 이 범위 넘어갈 수 없음

- "rows between 1 preceding and 1 following" -> 윈도우 크기는 위 아래 행 하나씩

=> sum()은 윈도우 기준으로, rank()/dense_rank()/row_number()은 분석대상 기준으로

- sum() 함수 실행: 75000_62000+62000=199000

 

(5) 5번째 행

- partition by: dept_name별로 소그룹 분류해둠

* "dept_name=Comp.Sci."인 행들 소그룹 -> 이제 함수들 실행할 윈도우 이 범위 넘어갈 수 없음

- "rows between 1 preceding and 1 following" -> 윈도우 크기는 위 아래 행 하나씩

=> sum()은 윈도우 기준으로, rank()/dense_rank()/row_number()은 분석대상 기준으로

- sum() 함수 실행: 62000+62000+92000=216000

 

(6) 6번째 행

- partition by: dept_name별로 소그룹 분류해둠

* "dept_name=Comp.Sci."인 행들 소그룹 -> 이제 함수들 실행할 윈도우 이 범위 넘어갈 수 없음

- "rows between 1 preceding and 1 following" -> 윈도우 크기는 위 아래 행 하나씩 -> (중요)BUT 아래 행은 partition by 범위 넘어가기 때문에 제외

=> sum()은 윈도우 기준으로, rank()/dense_rank()/row_number()은 분석대상 기준으로

- sum() 함수 실행: 65000+65000+75000=205000

<rank()>

: 각자 분석 대상 내 행들은 동일 순위

rank() over (partition by dept_name 
		rows between 1 preceding 
		and 1 following) as RANK_4

 

 

<dense_rank()>

각자 분석 대상 내 행들은 동일 순위

dense_rank() over (partition by dept_name 
		rows between 1 preceding 
		and 1 following) as DRANK_4

 

<row_number()>

: 각자 분석 대상 안에서만 순위 매김 -> 다른 분석 대상으로 넘어가면 1부터 다시 시작

row_number() over (partition by dept_name 
		rows between 1 preceding 
		and 1 following) as RNUM_4

 

 

<예제5>: 분석 대상 partition by + order by / 윈도우 크기 x

 

한 분석대상 안의 salary 컬럼이(partition by) 오름차순 정렬(order by)

 

소그룹 내에서 order by -> 동순위끼리만 윈도우 지정하고 연산하기 위해 순위 매김

윈도우 크기 명시 x -> 윈도우 크기는 처음행~동순위 행

 

(1) 1번째 행

- partition by: dept_name별로 소그룹 분류해둠

* "dept_name=Comp.Sci."인 행들 소그룹 -> 이제 함수들 실행할 윈도우 이 범위 넘어갈 수 없음

- order by: 소그룹 내에서 동순위 차등 부여

=> sum()은 윈도우 기준으로, rank()/dense_rank()/row_number()은 분석대상 기준으로

- sum(): 62000+62000=124000

 

(2) 2번째 행

- partition by: dept_name별로 소그룹 분류해둠

* "dept_name=Comp.Sci."인 행들 소그룹 -> 이제 함수들 실행할 윈도우 이 범위 넘어갈 수 없음

- order by: 소그룹 내에서 동순위 차등 부여

=> sum()은 윈도우 기준으로, rank()/dense_rank()/row_number()은 분석대상 기준으로

- sum(): 62000+62000=124000

 

 

(3) 3번째 행

- partition by: dept_name별로 소그룹 분류해둠

* "dept_name=Comp.Sci."인 행들 소그룹 -> 이제 함수들 실행할 윈도우 이 범위 넘어갈 수 없음

- order by: 소그룹 내에서 동순위 차등 부여

=> sum()은 윈도우 기준으로, rank()/dense_rank()/row_number()은 분석대상 기준으로

- sum(): 62000+62000+65000+65000=254000

 

(4) 4번째 행

- partition by: dept_name별로 소그룹 분류해둠

* "dept_name=Comp.Sci."인 행들 소그룹 -> 이제 함수들 실행할 윈도우 이 범위 넘어갈 수 없음

- order by: 소그룹 내에서 동순위 차등 부여

=> sum()은 윈도우 기준으로, rank()/dense_rank()/row_number()은 분석대상 기준으로

- sum(): 62000+62000+65000+65000=254000

(5) 5번째 행

- partition by: dept_name별로 소그룹 분류해둠

* "dept_name=Comp.Sci."인 행들 소그룹 -> 이제 함수들 실행할 윈도우 이 범위 넘어갈 수 없음

- order by: 소그룹 내에서 동순위 차등 부여

=> sum()은 윈도우 기준으로, rank()/dense_rank()/row_number()은 분석대상 기준으로

- sum(): 62000+62000+65000+65000+75000=329000

 

(6) 6번째 행

- partition by: dept_name별로 소그룹 분류해둠

* "dept_name=Comp.Sci."인 행들 소그룹 -> 이제 함수들 실행할 윈도우 이 범위 넘어갈 수 없음

- order by: 소그룹 내에서 동순위 차등 부여

=> sum()은 윈도우 기준으로, rank()/dense_rank()/row_number()은 분석대상 기준으로

- sum(): 62000+62000+65000+65000+75000+92000=421000

 

(7) 7번째 행

- partition by: dept_name별로 소그룹 분류해둠

* "dept_name=Comp.Sci."인 행들 소그룹 -> 이제 함수들 실행할 윈도우 이 범위 넘어갈 수 없음

- order by: 소그룹 내에서 동순위 차등 부여

=> sum()은 윈도우 기준으로, rank()/dense_rank()/row_number()은 분석대상 기준으로

- sum(): 80000+80000=160000

8~끝도 해보기

 

<rank()>

: 각자 분석 대상 내 행들 절대 순위 매김

 

<dense_rank()>

: 각자 분석 대상 내 행들 상대 순위 매김

 

<row_number()>

: 각자 분석 대상 안에서만 순위 매김 -> 다른 분석 대상으로 넘어가면 1부터 다시 시작

 

<예제6>: 분석 대상 partition by + order by / 윈도우 크기 명시

 

예제5에서 윈도우 크기가 위 아래 행 하나씩으로 명시되어 있는 예제다.

1행
2행
3행
4행
5행
6행
7행
8행
9행
10행
11행
12행

 

order by 존재하므로 rank(), dense_rank()은 한 분석 대상 내에서 순위가 매겨짐

 

<예제7>: 분석 대상 partition by + order by / 윈도우 크기 명시

 

윈도우 정의가 비어있을 때

-> 분석대상도, 윈도우 크기도 정해지지 않았기 때문에 전체 행을 하나의 윈도우이자 분석대상으로 본다.

전체 행이 동일 순위이기 때문에 rank(), dense_rank()은 모두 1이 되고, row_number()은 처음부터 끝까지 쭉 순위가 매겨진다.

또한 sum()은 전체 행의 salary값의 합이 된다.

'백엔드 > SQL' 카테고리의 다른 글

데이터베이스 설계와 개체-관계 모델  (0) 2025.05.27
SQL을 활용한 데이터 집계와 분석(2)  (0) 2025.05.26
JOIN  (0) 2025.04.17
DML: SQL 연산자와 내장함수(2)  (0) 2025.04.15
SQL 8장  (0) 2025.04.14