윈도우 함수(WINDOW 함수) 란?
윈도우 함수는 SQL에서 특정 데이터셋의 '윈도우'나 '프레임'에 대해 집계, 순위 및 분석 작업을 수행할 수 있는 강력한 도구이다. 이 함수들은 일반 집계 함수와 비슷하지만, 결과를 그룹화하지 않고 원본 데이터의 구조를 유지하면서 각 행에 대한 계산 결과를 반환할 수 있다는 차이점이 있다. 윈도우 함수는 주로 데이터의 특정 순위를 정하거나, 이동 평균을 계산하거나, 각 그룹 내에서의 행의 위치를 결정하는 등의 작업에 사용된다. 분석 함수 (ANALYTIC FUNCTION) 나 순위 함수 (RANK FUNCTION) 로도 알려져 있는 윈도우 함수는 데이터웨어하우스에서 발전한 기능이다.
복잡하거나 자원을 많이 사용하는 튜닝 기법들을 대체할 수 있는 DBMS의 새로운 기능은 튜닝 관점에서도 최적화된 방법이므로 적극적으로 활용할 필요가 있다. 같은 결과가 나오는 변형된 튜닝 문장보다는 DBMS 벤더에서 최적화된 자원을 사용하도록 만들어진 새로운 기능을 사용하는 것이 일반적으로 더욱 효과가 좋기 때문이다.
WINDOW 함수는 기존에 사용하던 집계 함수도 있고, 새로이 WINDOW 함수 전용으로 만들어진 기능도 있다. 그리고 WINDOW 함수는 다른 함수와는 달리 중첩(NEST)해서 사용하지는 못하지만 서브쿼리에서는 사용할 수 있다.
윈도우 함수 문법
SELECT WINDOW_FUNCTION (ARGUMENTS) OVER (
[PARTITION BY column1, column2, ...]
[ORDER BY column1 [ASC|DESC], column2 [ASC|DESC], ...]
[WINDOWING 절]
)
FROM TABLE;
WINDOWING 절
- 함수의 대상이 되는 행 기준의 범위를 강력하게 지정할 수 있다.
- 주로 ROWS 또는 RANGE 키워드를 사용하여 지정하며, 파티션 내의 데이터에 대해 어떻게 창(window)을 설정할지 정의한다.
- ROWS는 물리적인 결과 행의 수를, RANGE는 논리적인 값에 의한 범위를 나타내는데, 둘 중의 하나를 선택해서 사용할 수 있다.
- 다만, WINDOWING 절은 SQL Server에서는 지원하지 않는다.
RANK 함수
- ORDER BY 를 포함한 쿼리문에서 특정 항목 칼럼 에 대한 순위를 구하는 함수
- 특정 범위 (PARTITION) 내에서 순위를 구할 수도 있고 전체 데이터에 대한 순위를 구할 수도 있다.
- 동일한 값에 대해서는 동일한 순위를 부여하게 된다.
SELECT JOB, ENAME, SAL,
RANK() OVER (ORDER BY SAL DESC) ALL_RANK,
RANK() OVER (PARTITION BY JOB ORDER BY SAL DESC) JOB_RANK
FROM EMP;
JOB ENAME SAL ALL_RANK JOB_RANK
--- ------ --- --------- ---------
PRESIDENT KING 5000 1 1
ANALYST FORD 3000 2 1
ANALYST SCOTT 3000 2 1
MANAGER JONES 2975 4 1
MANAGER BLAKE 2850 5 2
MANAGER CLARK 2450 6 3
SALESMAN ALLEN 1600 7 1
SALESMAN TURNER 1500 8 2
CLERK MILLER 1300 9 1
SALESMAN WARD 1250 10 3
SALESMAN MARTIN 1250 10 3
CLERK ADAMS 1100 12 2
CLERK JAMES 950 13 3
CLERK SMITH 800 14 4
DENSE_RANK 함수
- RANK 함수와 같지만, 차이점은 동일한 등수가 나온만큼 카운트를 더하지 않고 연속적인 순위를 배정한다.
SELECT JOB, ENAME, SAL,
RANK() OVER (ORDER BY SAL DESC) RANK,
DENSE_RANK() OVER (ORDER BY SAL DESC) DENSE_RANK
FROM EMP;
JOB ENAME SAL RANK DENSE_RANK
--- ------ --- ----- -----------
PRESIDENT KING 5000 1 1
ANALYST FORD 3000 2 2
ANALYST SCOTT 3000 2 2
MANAGER JONES 2975 4 3
MANAGER BLAKE 2850 5 4
MANAGER CLARK 2450 6 5
SALESMAN ALLEN 1600 7 6
SALESMAN TURNER 1500 8 7
CLERK MILLER 1300 9 8
SALESMAN WARD 1250 10 9
SALESMAN MARTIN 1250 10 9
CLERK ADAMS 1100 12 10
CLERK JAMES 950 13 11
CLERK SMITH 800 14 12
ROW_NUMBER 함수
- RANK나 DENSE_RANK 함수가 동일한 값에 대해서는 동일한 순위를 부여하는데 반해, 동일한 값이라도 고유한 순위를 연속적으로 부여한다.
SELECT JOB, ENAME, SAL,
RANK() OVER (ORDER BY SAL DESC) RANK,
ROW_NUMBER() OVER (ORDER BY SAL DESC) ROW_NUMBER
FROM EMP;
JOB ENAME SAL RANK ROW_NUMBER
--- ------ --- ----- -----------
PRESIDENT KING 5000 1 1
ANALYST FORD 3000 2 2
ANALYST SCOTT 3000 2 3
MANAGER JONES 2975 4 4
MANAGER BLAKE 2850 5 5
MANAGER CLARK 2450 6 6
SALESMAN ALLEN 1600 7 7
SALESMAN TURNER 1500 8 8
CLERK MILLER 1300 9 9
SALESMAN WARD 1250 10 10
SALESMAN MARTIN 1250 10 11
CLERK ADAMS 1100 12 12
CLERK JAMES 950 13 13
CLERK SMITH 800 14 14
SUM 함수
예제 - 1
SELECT MGR, ENAME, SAL,
SUM(SAL) OVER (PARTITION BY MGR) MGR_SUM
FROM EMP;
MGR ENAME SAL MGR_SUM
---- ------ --- ---------
7566 FORD 3000 6000
7566 SCOTT 3000 6000
7698 JAMES 950 6550
7698 ALLEN 1600 6550
7698 WARD 1250 6550
7698 TURNER 1500 6550
7698 MARTIN 1250 6550
7782 MILLER 1300 1300
7788 ADAMS 1100 1100
7839 BLAKE 2850 8275
7839 JONES 2975 8275
7839 CLARK 2450 8275
7902 SMITH 800 800
KING 5000 5000
예제 - 1
SELECT MGR, ENAME, SAL,
SUM(SAL) OVER (
PARTITION BY MGR ORDER BY SAL RANGE UNBOUNDED PRECEDING
) as MGR_SUM
FROM EMP
RANGE UNBOUNDED PRECEDING
현재 행을 기준으로 파티션 내의 첫 번째 행까지의 범위를 지정한다. 현재 행에서 지정된 방향(여기서는 시작부터 현재 행까지)으로 데이터의 범위를 지정하는 데 사용되는데, 이 구문을 사용하면 현재 행을 포함하여 그 이전의 모든 행을 계산 범위로 포함한다.
RANGE UNBOUNDED PRECEDING
정렬 기준의 값이 같은 모든 행을 포함하여 계산한다.
즉, 동일한 값에 대해 경계가 확장된다.
ROWS UNBOUNDED PRECEDING
물리적인 행의 수를 기준으로 하여 계산한다.
즉, 동일한 값이어도 상관없이 순서대로 지정된 행만큼만 포함한다.
MGR ENAME SAL MGR_SUM
---- ------ --- ---------
7566 SCOTT 3000 6000
7566 FORD 3000 6000
7698 JAMES 950 950
7698 WARD 1250 3450
7698 MARTIN 1250 3450
7698 TURNER 1500 4950
7698 ALLEN 1600 6550
7782 MILLER 1300 1300
7788 ADAMS 1100 1100
7839 CLARK 2450 2450
7839 BLAKE 2850 5300
7839 JONES 2975 8275
7902 SMITH 800 800
KING 5000 5000
MAX / MIN 함수
- 파티션별 윈도우의 최대/최소값을 구할 수 있다.
- 다음은 INLINE VIEW를 이용해 파티션별 최대값을 가진 행만 추출하는 예제이다.
SELECT MGR, ENAME, SAL
FROM (
SELECT MGR, ENAME, SAL,
MAX(SAL) OVER (PARTITION BY MGR) as IV_MAX_SAL
FROM EMP
)
WHERE SAL = IV_MAX_SAL ;
MGR ENAME SAL
---- ------ ---
7566 FORD 3000
7566 SCOTT 3000
7698 ALLEN 1600
7782 MILLER 1300
7788 ADAMS 1100
7839 JONES 2975
7902 SMITH 800
KING 5000
AVG 함수
SELECT MGR, ENAME, HIREDATE, SAL,
ROUND (AVG(SAL) OVER (
PARTITION BY MGR ORDER BY HIREDATE
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)) as MGR_AVG
FROM EMP;
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
현재 행을 기준으로 파티션 내에서 앞의 한 건, 현재 행, 뒤의 한 건을 범위로 지정한다.
MGR ENAME HIREDATE SAL MGR_AVG
---- ------ --------- --- ---------
7566 FORD 1981-12-03 3000 3000
7566 SCOTT 1987-07-13 3000 3000
7698 ALLEN 1981-02-20 1600 1425
7698 WARD 1981-02-22 1250 1450
7698 TURNER 1981-09-08 1500 1333
7698 MARTIN 1981-09-28 1250 1233
7698 JAMES 1981-12-03 950 1100
7782 MILLER 1982-01-23 1300 1300
7788 ADAMS 1987-07-13 1100 1100
7839 JONES 1981-04-02 2975 2913
7839 BLAKE 1981-05-01 2850 2758
7839 CLARK 1981-06-09 2450 2650
7902 SMITH 1980-12-17 800 800
KING 1981-11-17 5000 5000
COUNT 함수
SELECT ENAME, SAL,
COUNT(*) OVER (
ORDER BY SAL
RANGE BETWEEN 50 PRECEDING AND 150 FOLLOWING) as SIM_CNT
FROM EMP;
RANGE BETWEEN 50 PRECEDING AND 150 FOLLOWING
현재 행의 급여값을 기준으로 급여가 -50 에서 +150 의 범위 내에 포함된 모든 행이 대상이 된다.
ENAME SAL SIM_CNT (범위 값)
------ --- --- -------
SMITH 800 2 ( 750~ 950)
JAMES 950 2 ( 900~1100)
ADAMS 1100 3 (1050~1250)
WARD 1250 3 (1200~1400)
MARTIN 1250 3 (1200~1400)
MILLER 1300 3 (1250~1450)
TURNER 1500 2 (1450~1650)
ALLEN 1600 1 (1550~1750)
CLARK 2450 1 (2400~2600)
BLAKE 2850 4 (2800~3000)
JONES 2975 3 (2925~3125)
SCOTT 3000 3 (2950~3100)
FORD 3000 3 (2950~3100)
KING 5000 1 (4950~5100)
FIRST_VALUE 함수
- 파티션별 윈도우에서 가장 먼저 나온 값을 구한다.
- SQL Server 에서는 지원하지 않는 함수이다.
- MIN 함수를 활용하여 같은 결과를 얻을 수도 있다.
SELECT DEPTNO, ENAME, SAL,
FIRST_VALUE(ENAME)
OVER (
PARTITION BY DEPTNO ORDER BY SAL DESC
ROWS UNBOUNDED PRECEDING
) as DEPT_RICH
FROM EMP;
ROWS UNBOUNDED PRECEDING
현재 행을 기준으로 파티션 내의 첫 번째 행까지의 범위를 지정한다. (현재 행부터 파티션의 시작점까지 모든 행을 참조)
DEPTNO ENAME SAL DEPT_RICH
------ ------ --- ---------
10 KING 5000 KING
10 CLARK 2450 KING
10 MILLER 1300 KING
20 SCOTT 3000 SCOTT
20 FORD 3000 SCOTT
20 JONES 2975 SCOTT
20 ADAMS 1100 SCOTT
20 SMITH 800 SCOTT
30 BLAKE 2850 BLAKE
30 ALLEN 1600 BLAKE
30 TURNER 1500 BLAKE
30 MARTIN 1250 BLAKE
30 WARD 1250 BLAKE
30 JAMES 950 BLAKE
LAST_VALUE 함수
- 파티션별 윈도우에서 가장 나중에 나온 값을 구한다.
- SQL Server 에서는 지원하지 않는 함수이다.
- MAX 함수를 활용하여 같은 결과를 얻을 수도 있다.
SELECT DEPTNO, ENAME, SAL,
LAST_VALUE(ENAME) OVER (
PARTITION BY DEPTNO ORDER BY SAL DESC
ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) as DEPT_POOR
FROM EMP;
ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
현재 행을 포함해서 파티션 내의 마지막 행까지의 범위를 지정한다.
DEPTNO ENAME SAL DEPT_POOR
------ ------ --- ----------
10 KING 5000 MILLER
10 CLARK 2450 MILLER
10 MILLER 1300 MILLER
20 SCOTT 3000 SMITH
20 FORD 3000 SMITH
20 JONES 2975 SMITH
20 ADAMS 1100 SMITH
20 SMITH 800 SMITH
30 BLAKE 2850 JAMES
30 ALLEN 1600 JAMES
30 TURKER 1500 JAMES
30 MARTIN 1250 JAMES
30 WARD 1250 JAMES
30 JAMES 950 JAMES
LAG / LEAD함수
- 파티션별 윈도우에서 이전/이후 몇 번째 행의 값을 가져올 수 있다.
- SQL Server 에서는 지원하지 않는 함수이다.
예제 - 1
SELECT ENAME, HIREDATE, SAL,
LAG(SAL) OVER (ORDER BY HIREDATE) as PREV_SAL
FROM EMP
WHERE JOB = 'SALESMAN' ;
ENAME HIREDATE SAL MGR_MIN
----- -------- --- ---------
ALLEN 1981-02-20 1600
WARD 1981-02-22 1250 1600
TURNER 1981-09-08 1500 1250
MARTIN 1981-09-28 1250 1500
예제 - 2
SELECT ENAME, HIREDATE, SAL,
LAG(SAL, 2, 0) OVER (ORDER BY HIREDATE) as PREV_SAL
FROM EMP
WHERE JOB = 'SALESMAN'
LAG(SAL, 2, 0)
두 행 앞의 SALARY를 가져오고 가져올 값이 없는 경우는 0으로 처리한다.
ENAME HIREDATE SAL PREV_SAL
----- -------- --- --------
ALLEN 1981-02-20 1600 0
WARD 1981-02-22 1250 0
TURNER 1981-09-08 1500 1600
MARTIN 1981-09-28 1250 1250
예제 - 3
SELECT ENAME, HIREDATE,
LEAD (HIREDATE, 1) OVER (ORDER BY HIREDATE) as "NEXTHIRED"
FROM EMP;
ENAME HIREDATE NEXTDATE
----- -------- --------
ALLEN 1981-02-20 1981-02-22
WARD 1981-02-22 1981-04-02
TURNER 1981-09-08 1981-09-28
MARTIN 1981-09-28
< 그룹 내 비율 함수 >
RATIO_TO_REPORT 함수
- 파티션 내 전체 SUM(칼럼)값에 대한 행별 칼럼 값의 백분율을 소수점으로 구할 수 있다.
- 결과 값은 >0 & <=1 의 범위를 가진다.
- 그리고 개별 RATIO 의 합을 구하면 1이 된다.
- SQL Server 에서는 지원하지 않는 함수이다.
SELECT ENAME, SAL,
ROUND(RATIO_TO_REPORT(SAL) OVER (), 2) as R_R
FROM EMP
WHERE JOB = 'SALESMAN';
ENAME SAL R_R
----- --- ----
ALLEN 1600 0.29 (1600 / 5600)
WARD 1250 0.22 (1250 / 5600)
TURNER 1250 0.22 (1250 / 5600)
MARTIN 1500 0.27 ( 500 / 5600)
PERCENT_RANK 함수
- 파티션별 윈도우에서 제일 먼저 나오는 것을 0으로, 제일 늦게 나오는 것을 1로 하여, 값이 아닌 행의 순서별 백분율을 구한다.
- 결과 값은 >=0 & <=1 의 범위를 가진다.
- SQL Server 에서는 지원하지 않는 함수이다.
SELECT DEPTNO, ENAME, SAL,
PERCENT_RANK() OVER (
PARTITION BY DEPTNO ORDER BY SAL DESC
) as P_R
FROM EMP;
DEPTNO ENAME SAL P_R
------ ----- --- ---
10 KING 5000 0
10 CLARK 2450 0.5
10 MILLER 1300 1
20 SCOTT 3000 0
20 FORD 3000 0
20 JONES 2975 0.5
20 ADAMS 1100 0.75
20 SMITH 800 1
30 BLAKE 2850 0
30 ALLEN 1600 0.2
30 TURKER 1500 0.4
30 MARTIN 1250 0.6
30 WARD 1250 0.6
30 JAMES 950 1
CUME_DIST 함수
- 파티션별 윈도우의 전체건수에서 현재 행보다 작거나 같은 건 수에 대한 누적백분율을 구한다.
- 결과 값은 >0 & <=1의 범위를 가진다.
- SQL Server 에서는 지원하지 않는 함수이다.
SELECT DEPTNO, ENAME, SAL,
CUME_DIST() OVER (
PARTITION BY DEPTNO ORDER BY SAL DESC
) as CUME_DIST
FROM EMP;
DEPTNO ENAME SAL CUME_DIST
------ ----- --- ----------
10 KING 5000 0.3333
10 CLARK 2450 0.6667
10 MILLER 1300 1.0000
20 SCOTT 3000 0.4000
20 FORD 3000 0.4000
20 JONES 2975 0.6000
20 ADAMS 1100 0.8000
20 SMITH 800 1.0000
30 BLAKE 2850 0.1667
30 ALLEN 1600 0.3333
30 TURKER 1500 0.5000
30 MARTIN 1250 0.8333
30 WARD 1250 0.8333
30 JAMES 950 1.0000
NTILE 함수
- 파티션별 전체 건수를 ARGUMENT 값으로 N등분한 결과를 구할 수 있다.
SELECT ENAME, SAL,
NTILE(4) OVER (ORDER BY SAL DESC) as QUAR_TILE
FROM EMP
DEPTNO ENAME SAL QUAR_TILE
------ ----- --- ----------
10 KING 5000 1
10 FORD 3000 1
10 SCOTT 3000 1
20 JONES 2975 1
20 BLAKE 2850 2
20 CLARK 2450 2
20 ALLEN 1600 2
20 TURNER 1500 2
30 MILLER 1300 3
30 WARD 1250 3
30 MARTIN 1250 3
30 ADAMS 1100 4
30 JAMES 950 4
30 SMITH 800 4
'DataBase > SQLD' 카테고리의 다른 글
옵티마이저(Optimizer) (1) | 2024.04.28 |
---|---|
절차형 SQL (0) | 2024.04.27 |
그룹함수(Group Function) (0) | 2024.04.26 |
서브쿼리(Subquery) (2) | 2024.04.26 |
계층형 질의(Hierarchical Query) - Oracle (0) | 2024.04.26 |