SQL 이것저것

[SQL] 윈도우 함수

agingcurve 2022. 9. 14. 09:31
반응형

데이터 분석을 위한 함수

 - 윈도우 함수 (Window fuction)

 - 집계 함수 (Aggregate function)

 - 그룹 함수 (Group function)

 

윈도우 함수

 - 행과 행간의 관계를 만들어주는 함수 (RANK, DENSE-RANK)

 - 순위, 집계 등 행과 행 사이의 관계를 정의하는 함수 OVER 구문을 필수로 한다

SELECT WINDOW_FUNCTION (ARGUMENTS)
OVER ( [PARTITION BY 칼럼] [ORDER BY 절] [WINDOWING 절] ) FROM 테이블 명;

 - ARGUMENTS : 윈도우 함수에 따라서 필요한 인수

 - PARTITION BY : 전체 집합에 대해 소그룹으로 나누는 기준 (특정 컬럼에 대해 기준을 설정해줄 수 있음)

 - ORDER BY : 소그룹에 대한 정렬 기준

 - WINDOWING : 행에 대한 범위 기준 

 

WINDOWING에 사용되는 인수

 - ROWS : 물리적 단위로 행의 집합을 지정

 - UNBOUNDED PRECEDING : 윈도우의 시작 위치가 첫 번째 행

 - UNBOUNDED FOLLOWING : 윈도우의 마지막 위치가 마지막 행

 - CURRENT ROW : 윈도우의 시작 위치가 현재 행

 

순위 함수

 - RANK : 동일한 값에는 동일한 순위를 부여

 - DENSE_RANK : RANK와 같이 같은 값에는 같은 순위를 부여하나 한 건으로 취급

 - ROW_NUMBER : 동일한 값이라도 고유한 순위를 부여

RANK() OVER ([PARTITION BY 컬럼 ][ORDER BY 컬럼 ][WINDOWING 절] )

 

SELECT ID, NAME, SALARY,
RANK() OVER (ORDER BY SALARY DESC) RANK,
DENSE_RANK() OVER (ORDER BY SALARY DESC) DENSED_RANKING,
ROW_NUMBER() OVER (ORDER BY SALARY DESC) ROW_NUMBER
FROM EMPLOYEE;

기준이 되는 컬럼의 값이 동일할때, RANK의 경우, 다건으로 취급하여 동일한 값을 부여하고, 이후 값을 5로 부여하게 되고 DENSE_RANK는 단건으로 취급하여 다음 값이 4를 부여하게 된다.

 

 

일반 집계 함수 (예제)

일반 집계 함수(SUM, AVG, MAX, MIN, …)를 GROUP BY 구문 없이 사용할 수 있다

# 스칼라 서브쿼리를 이용하여 AVG를 구하고 있음
SELECT ID, NAME, SALARY, DEPARTMENT_ID,
(SELECT AVG(SALARY) FROM EMPLOYEE B
WHERE B.DEPARTMENT_ID = A.DEPARTMENT_ID) DEPARTMENT_AVG
FROMEMPLOYEE A
ORDER BY A.DEPARTMENT_ID;

# OVER 구문을 통해서 소그룹을 이용하여 DEPARTMENT_AVG를 이용하여 표시함
SELECT ID, NAME, SALARY,
AVG(SALARY) OVER (PARTITION BY DEPARTMENT_ID) DEPARTMENT_AVG
FROM EMPLOYEE;

 

그룹 내 행 순서 함수

 

FIRST_VALUE : 가장 먼저 나온 값을 구한다

LAST_VALUE : 가장 나중에 나온 값을 구한다

LAG : 이전 X 번째 행을 가져온다

LEAD : 이후 X 번째 행을 가져온다

 

 

FIRST_VALUE, LAST_VALUE

각 부서에서 급여를 가장 많이 받은 사람의 급여와, 가장 적게 받는 사람의 급여를 함께 출력

SELECT
ID, DEPARTMENT_ID, NAME, SALARY, 
FIRST_VALUE(SALARY) OVER(PARTITION BY DEPARTMENT_ID ORDER BY SALARY
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) DEPARTMENT_MIN_SALARY ,
LAST_VALUE(SALARY) OVER(PARTITION BY DEPARTMENT_ID ORDER BY SALARY
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) DEPARTMENT_MAX_SALARY
FROM EMPLOYEE
ORDER BY ID;

 

DEPARTMENT_ID 기준으로 SALARY 값을 보게 되었을 때, 

DEPARTMENT_ID 그룹을 형성하고 그 사이 

UNBOUNDED PROCEDING 은 첫 값, UNBOUNDED FOLLWING 은 마지막 값을 통해서 최소값과 최대값을 뽑게 된다.

 

SELECT
ID, DEPARTMENT_ID, NAME, SALARY, FIRST_VALUE(SALARY)
OVER(PARTITION BY DEPARTMENT_ID ORDER BY SALARY
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS DEPARTMENT_MIN_SALARY ,
LAST_VALUE(SALARY)
OVER(PARTITION BY DEPARTMENT_ID ORDER BY SALARY
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
AS DEPARTMENT_MAX_SALARY
FROM EMPLOYEE
ORDER BY ID

 

 

UNDERBOUND 절에 CURRENT ROW 절을 넣게된다면, 현재 자신의 절에 대해서 최댓값과 최소값을 구해지게 되기때문에 해당 값으로 변화된다.

SELECT
ID, DEPARTMENT_ID, NAME, SALARY, FIRST_VALUE(SALARY)
OVER(PARTITION BY DEPARTMENT_ID ORDER BY SALARY
ROWS BETWEEN CURRENT ROW PRECEDING AND CURRENT ROW FOLLOWING) AS DEPARTMENT_MIN_SALARY ,
LAST_VALUE(SALARY)
OVER(PARTITION BY DEPARTMENT_ID ORDER BY SALARY
ROWS BETWEEN CURRENT ROW PRECEDING AND CURRENT ROW FOLLOWING)
AS DEPARTMENT_MAX_SALARY
FROM EMPLOYEE
ORDER BY ID

 

 

LAG, LEAD

앞/뒤 X번째 행(값)을 불러온다

SELECT ID, NAME, SALARY, 
LAG(NAME, 1) OVER(ORDER BY ID) PREV_EMPLOYEE_NAME,
LEAD(NAME, 1) OVER(ORDER BY ID) AFTER_EMPLOYEE_NAME
FROM EMPLOYEE;

 

그룹 내 비율 함수

RATIO_TO_REPORT : 파티션 내 전체 SUM에 대한 비율을 구한다

PERCENT_RANK : 파티션 내 순위를 백분율로 구한다

CUME_DIST : 파티션 내 현재 행보다 작거나 같은 건들의 수 누적 백분율로 구한다

NTILE : 파티션 내 행들을 N등분한 결과를 구한다

 

RATIO_TO_REPORT

직원 전체 급여의 합 중 각 행이 차지하는 비율을 출력

SELECT ID, NAME, SALARY,
SUM(SALARY) OVER() TOTAL_SALARY,
RATIO_TO_REPORT(SALARY) OVER() RATIO_TO_REPORT
FROM EMPLOYEE;

 

RATIO_TO_REPORT-MariaDB

현재 MariaDB에서 RATIO_TO_REPORT는 제공되지 않기에 명시적으로 구현 가능한다

SELECT ID, NAME, SALARY,
SUM(SALARY) OVER() TOTAL_SALARY,
(SALARY / SUM(SALARY) OVER()) RATIO_TO_REPORT
FROM EMPLOYEE;

 

PERCENT_RANK, CUME_DIST

PERCENT_RANK는 순위를 백분율로 나타내며 제일 높은 순위 행은 0, 가장 낮은 순위 행은 1을 가진다 CUME_DIST는 현재 행보다 같거나 낮은 값들을 가지는 행들의 누적 백분율 값을 나타낸다.

SELECT ID, NAME, SALARY,
PERCENT_RANK() OVER(ORDER BY SALARY DESC)
AS PERCENT_RANK,
ROUND(CUME_DIST() OVER(ORDER BY SALARY DESC), 4)
AS CUME_DIST
FROM EMPLOYEE;

NTILE(숫자가 오는 것은 몇개의 그룹으로 값을 분류함)

급여에 따라 직원들을 세 그룹으로 분류

SELECT ID, NAME, SALARY,
NTILE(3) OVER(ORDER BY SALARY DESC) NTILE
FROM EMPLOYEE;

'SQL 이것저것' 카테고리의 다른 글

[SQL] 데이터베이스 준비하기  (0) 2022.09.16
[SQL] 그룹 함수  (0) 2022.09.16
[SQL] View(뷰)  (0) 2022.09.10
[SQL] 서브쿼리  (0) 2022.09.10
[SQL] JOIN  (0) 2022.08.30