1. Window Function 개요
윈도우 함수랑 행과 행간의 관계를 쉽게 정의하기 위해 만든 함수를 말한다. 분석 함수(ANALYSTIC FUNCTION)이나 순위 함수(RANK FUNCTION)등이 해당된다. 서브쿼리는 사용이 가능하고, 중첩(NEST)해서는 사용이 불가하다.
WINDOW FUNCTION 종류
| 구분 | 함수 | 지원 정보 |
| 그룹 내 순위(RANK) 관련 함수 | RANK, DENSE_RANK, ROW_NUMBER | ANSI/ISO SQL 표준과 Oracle, SQL Sever등 대부분의 DBMS에서 지원 |
| 그룹 내 집계(AGGREGATE) 관련 함수 | SUM ,MAX, MIN, AVG, COUNT | ANSI/ISO SQL 표준과 Oracle, SQL Server 등 대부분의 DBMS 에서 지원 SQL Server 의 경우 집계 함수는 뒤에서 설명할 OVER 절의 내의 ORDER BY 지원 하지 않음 |
| 그룹 내 행 순서 관련 함수 | FIRST_VALUE, LAST_VALUE, LAG, LEAD | ORACLE에서만 지원 |
| 그룹 내 비율 관련 함수 |
CUME_DIST, PERCENT_RANK | ANSI/ISO SQL 표준과 Oracle, MS SQL에서 지원 |
| NTILE | ORACLE, MS SQL에서 지원 | |
| RATIO_TO_REPORT | ORACLE 에서만 지원 |
SYNTAX
SELECT WINDOW_FUNCTION (ARGUMENTS) OVER
( [PARTITION BY 컬럼][ORDER BY 절][WINDOWING 절])
FROM 테이블 명;
-- WINDOW_FUNCTION : 윈도우함수
-- ARGUMENTS : 함수에 따라 0~N개의 인수가 저장
-- OVER : Window 함수 사용에 있어 OVER 문구는 필수 키워드이다.
-- PARTITION BY 절 : 전체 집합을 기준에 대해 순위를 지정할 지 ORDER BY 절을 기술
-- WINDOWING절 : WINDOWS 절은 함수의 대상이 되는 행 기준의 범위를 강력하게 지정할 수 있다.
--ROWS는 물리적인 결과 행의 수, RANGE는 논리적인 값에 의한 범위를, 둘 중 하나 선택 사용
--WINDOWING절은 SQL Server에서는 지원하지 않는다.
WINDOWING 절 SYNTAX 상세
ROWS | RANGE BETWEEN UNBOUNDED PRECEDING[CURRENT ROW] AND UNBOUNDED FOLLOWING[CURRENT ROW]
ROWS : 물리적인 행을 의미
RANGE : 논리적인 값으로 범위를 지정 / 같은값을 하나로 본다
WINDOWINDG 기본 설정값이 존재 : UNBOUNDED PRECEDING
UNBOUNDED PRECEDING : 현재행을 기준으로 선행(이전)하는 모든 행들
SELECT empno, ename, sal ,
SUM(sal) OVER (ORDER BY sal ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) c_sum
FROM emp
ORDER BY sal;
UNBOUNDED FOLLOWING : 현재행을 기준으로 이후 모든 행들
n PRECEDING : 현재행을 기준으로 n칸 앞
n FOLLWING : 현재행을 기준으로 n칸 뒤
FIRST_VALUE
파티션 별 윈도우에서 가장 먼저 나온 값을 구한다.
FIRST_VALUE는 공동 등수를 인정하지 않고 처음 나온 행만을 구한다.
부서별로 나누어진 윈도우에서 가장 먼저 나온 사람의 이름을 구하는 예제
SELECT EMPLOYEE_ID, DEPARTMENT_ID, FIRST_NAME, SALARY,
FIRST_VALUE(FIRST_NAME) OVER ( PARTITION BY DEPARTMENT_ID ) AS Fisrst_name
FROM EMPLOYEES e ;
EMPLOYEE_ID|DEPARTMENT_ID|FIRST_NAME |SALARY|FISRST_NAME|
-----------+-------------+-----------+------+-----------+
200| 10|Jennifer | 4400|Jennifer |
201| 20|Michael | 13000|Michael |
202| 20|Pat | 6000|Michael |
114| 30|Den | 11000|Den |
115| 30|Alexander | 3100|Den |
116| 30|Shelli | 2900|Den |
117| 30|Sigal | 2800|Den |
118| 30|Guy | 2600|Den |
119| 30|Karen | 2500|Den |
203| 40|Susan | 6500|Susan |
120| 50|Matthew | 8000|Matthew |
121| 50|Adam | 8200|Matthew |
122| 50|Payam | 7900|Matthew |
123| 50|Shanta | 6500|Matthew |
...
order by를 사용하여 급여로 정렬 후 같은 부서내에서 연봉이 가장 작은 사람중 한명의 이름을 구하는 예제
SELECT EMPLOYEE_ID, DEPARTMENT_ID, FIRST_NAME, SALARY,
FIRST_VALUE(FIRST_NAME) OVER ( PARTITION BY DEPARTMENT_ID ORDER BY SALARY ) AS Fisrst_name
FROM EMPLOYEES e ;
EMPLOYEE_ID|DEPARTMENT_ID|FIRST_NAME |SALARY|FISRST_NAME|
-----------+-------------+-----------+------+-----------+
200| 10|Jennifer | 4400|Jennifer |
202| 20|Pat | 6000|Pat |
201| 20|Michael | 13000|Pat |
119| 30|Karen | 2500|Karen |
118| 30|Guy | 2600|Karen |
117| 30|Sigal | 2800|Karen |
116| 30|Shelli | 2900|Karen |
115| 30|Alexander | 3100|Karen |
114| 30|Den | 11000|Karen |
203| 40|Susan | 6500|Susan |
132| 50|TJ | 2100|TJ |
136| 50|Hazel | 2200|TJ |
128| 50|Steven | 2200|TJ |
...
LAST_VALUE
파티션 별 윈도우에서 가장 나중에 나온 값을 구한다.
부서별로 나누어진 사원들 중 가장 나중의 사원 이름을 구하는 예
SELECT EMPLOYEE_ID, DEPARTMENT_ID, FIRST_NAME, SALARY,
LAST_VALUE(FIRST_NAME) OVER ( PARTITION BY DEPARTMENT_ID ) AS Fisrst_name
FROM EMPLOYEES e ;
EMPLOYEE_ID|DEPARTMENT_ID|FIRST_NAME |SALARY|FISRST_NAME|
-----------+-------------+-----------+------+-----------+
200| 10|Jennifer | 4400|Jennifer |
201| 20|Michael | 13000|Pat |
202| 20|Pat | 6000|Pat |
114| 30|Den | 11000|Karen |
115| 30|Alexander | 3100|Karen |
116| 30|Shelli | 2900|Karen |
117| 30|Sigal | 2800|Karen |
118| 30|Guy | 2600|Karen |
119| 30|Karen | 2500|Karen |
203| 40|Susan | 6500|Susan |
...
부서별 직원들의 연봉이 높은 순서 부터 정렬하고, 파티션 내에서 가장 마지막에 나온 사원의 이름을 출력
SELECT EMPLOYEE_ID, DEPARTMENT_ID, FIRST_NAME, SALARY,
LAST_VALUE(FIRST_NAME) OVER ( PARTITION BY DEPARTMENT_ID ORDER BY SALARY DESC
ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) AS Fisrst_name
FROM EMPLOYEES e ;
EMPLOYEE_ID|DEPARTMENT_ID|FIRST_NAME |SALARY|FISRST_NAME|
-----------+-------------+-----------+------+-----------+
200| 10|Jennifer | 4400|Jennifer |
201| 20|Michael | 13000|Pat |
202| 20|Pat | 6000|Pat |
114| 30|Den | 11000|Karen |
115| 30|Alexander | 3100|Karen |
116| 30|Shelli | 2900|Karen |
117| 30|Sigal | 2800|Karen |
118| 30|Guy | 2600|Karen |
119| 30|Karen | 2500|Karen |
203| 40|Susan | 6500|Susan |
...
윈도우잉 절을 기술하지 않으면 다음과 같이 자기 자신의 로우까지 가장 마지막값으로 여긴다.
SELECT EMPLOYEE_ID, DEPARTMENT_ID, FIRST_NAME, SALARY,
LAST_VALUE(FIRST_NAME) OVER ( PARTITION BY DEPARTMENT_ID ORDER BY SALARY DESC ) AS Fisrst_name
FROM EMPLOYEES e ;
EMPLOYEE_ID|DEPARTMENT_ID|FIRST_NAME |SALARY|FISRST_NAME|
-----------+-------------+-----------+------+-----------+
200| 10|Jennifer | 4400|Jennifer |
201| 20|Michael | 13000|Michael |
202| 20|Pat | 6000|Pat |
114| 30|Den | 11000|Den |
115| 30|Alexander | 3100|Alexander |
116| 30|Shelli | 2900|Shelli |
117| 30|Sigal | 2800|Sigal |
118| 30|Guy | 2600|Guy |
119| 30|Karen | 2500|Karen |
203| 40|Susan | 6500|Susan |
...
NTH_VALUE
파티션 별 윈도우에서 n 번째를 지정하여 값을 가져올 수 있다.
SELECT EMPLOYEE_ID, DEPARTMENT_ID, FIRST_NAME, SALARY,
NTH_VALUE(FIRST_NAME, 2) OVER ( PARTITION BY DEPARTMENT_ID ORDER BY SALARY DESC ) AS Fisrst_name
FROM EMPLOYEES e ;
LAG
파티션별 윈도우에서 이전 몇 번째 행의 값을 가져올 수 있다.
*LAG ( 인수1, 인수2, 인수3)
- 인수1 : 입력 컬럼
- 인수2 : 몇 번째 앞의 행을 가져올 지 결정 ( DEFAULT 1)
- 인수3 : 파티션의 첫 번째 행의 경우 가져올 데이터가 없어 NULL값일 경우, 변경할 값 입력
사원들을 입사일자가 빠른 기준으로 정렬하고, 본인 보다 입사일자가 한 명 앞선 사원의 급여를 본인 급여와 함께 출력하는 예제
SELECT FIRST_NAME, HIRE_DATE, JOB_ID, SALARY, LAG(SALARY) OVER ( ORDER BY HIRE_DATE ) AS PREV_SAL
FROM EMPLOYEES e
WHERE JOB_ID ='SA_REP';
FIRST_NAME |HIRE_DATE |JOB_ID|SALARY|PREV_SAL|
-----------+-----------------------+------+------+--------+
Janette |2004-01-30 00:00:00.000|SA_REP| 10000| |
Patrick |2004-03-04 00:00:00.000|SA_REP| 9500| 10000|
Ellen |2004-05-11 00:00:00.000|SA_REP| 11000| 9500|
Allan |2004-08-01 00:00:00.000|SA_REP| 9000| 11000|
Peter |2005-01-30 00:00:00.000|SA_REP| 10000| 9000|
Lindsey |2005-03-10 00:00:00.000|SA_REP| 8000| 10000|
Lisa |2005-03-11 00:00:00.000|SA_REP| 11500| 8000|
Alyssa |2005-03-19 00:00:00.000|SA_REP| 8800| 11500|
David |2005-03-24 00:00:00.000|SA_REP| 9500| 8800|
Peter |2005-08-20 00:00:00.000|SA_REP| 9000| 9500|
Clara |2005-11-11 00:00:00.000|SA_REP| 10500| 9000|
...
사원들을 입사일자가 빠른 기준으로 정렬하고, 본인 보다 입사일자가 두 단계 앞선 사원의 급여를 본인 급여와 함께 출력하는 예제
SELECT FIRST_NAME, HIRE_DATE, JOB_ID, SALARY, LAG(SALARY, 2) OVER ( ORDER BY HIRE_DATE ) AS PREV_SAL
FROM EMPLOYEES e
WHERE JOB_ID ='SA_REP';
FIRST_NAME |HIRE_DATE |JOB_ID|SALARY|PREV_SAL|
-----------+-----------------------+------+------+--------+
Janette |2004-01-30 00:00:00.000|SA_REP| 10000| |
Patrick |2004-03-04 00:00:00.000|SA_REP| 9500| |
Ellen |2004-05-11 00:00:00.000|SA_REP| 11000| 10000|
Allan |2004-08-01 00:00:00.000|SA_REP| 9000| 9500|
Peter |2005-01-30 00:00:00.000|SA_REP| 10000| 11000|
Lindsey |2005-03-10 00:00:00.000|SA_REP| 8000| 9000|
Lisa |2005-03-11 00:00:00.000|SA_REP| 11500| 10000|
Alyssa |2005-03-19 00:00:00.000|SA_REP| 8800| 8000|
David |2005-03-24 00:00:00.000|SA_REP| 9500| 11500|
Peter |2005-08-20 00:00:00.000|SA_REP| 9000| 8800|
Clara |2005-11-11 00:00:00.000|SA_REP| 10500| 9500|
Louise |2005-12-15 00:00:00.000|SA_REP| 7500| 9000|
...
* 맨 위 없는 값들에 대해 NULL 대신 0 출력
SELECT FIRST_NAME, HIRE_DATE, JOB_ID, SALARY, LAG(SALARY, 2, 0) OVER ( ORDER BY HIRE_DATE ) AS PREV_SAL
FROM EMPLOYEES e
WHERE JOB_ID ='SA_REP';
FIRST_NAME |HIRE_DATE |JOB_ID|SALARY|PREV_SAL|
-----------+-----------------------+------+------+--------+
Janette |2004-01-30 00:00:00.000|SA_REP| 10000| 0|
Patrick |2004-03-04 00:00:00.000|SA_REP| 9500| 0|
Ellen |2004-05-11 00:00:00.000|SA_REP| 11000| 10000|
Allan |2004-08-01 00:00:00.000|SA_REP| 9000| 9500|
Peter |2005-01-30 00:00:00.000|SA_REP| 10000| 11000|
Lindsey |2005-03-10 00:00:00.000|SA_REP| 8000| 9000|
Lisa |2005-03-11 00:00:00.000|SA_REP| 11500| 10000|
Alyssa |2005-03-19 00:00:00.000|SA_REP| 8800| 8000|
David |2005-03-24 00:00:00.000|SA_REP| 9500| 11500|
Peter |2005-08-20 00:00:00.000|SA_REP| 9000| 8800|
Clara |2005-11-11 00:00:00.000|SA_REP| 10500| 9500|
...
LEAD
파티션 별 윈도우에서 이후 몇 번째 행의 값을 가져 올 수 있다.
*LEAD ( 인수1, 인수2, 인수3)
- 인수1 : 입력 컬럼
- 인수2 : 몇 번째 앞의 행을 가져올 지 결정 ( DEFAULT 1)
- 인수3 : 파티션의 첫 번째 행의 경우 가져올 데이터가 없어 NULL값일 경우, 변경할 값 입력
입사일자로 정렬 후 현재 로우 보다 입사일자가 한 단계 뒤에있는 사원의 급여를 구하는 예제
SELECT FIRST_NAME, HIRE_DATE, JOB_ID, SALARY, LEAD(SALARY) OVER ( ORDER BY HIRE_DATE ) AS PREV_SAL
FROM EMPLOYEES e
WHERE JOB_ID ='SA_REP';
FIRST_NAME |HIRE_DATE |JOB_ID|SALARY|PREV_SAL|
-----------+-----------------------+------+------+--------+
Janette |2004-01-30 00:00:00.000|SA_REP| 10000| 9500|
Patrick |2004-03-04 00:00:00.000|SA_REP| 9500| 11000|
Ellen |2004-05-11 00:00:00.000|SA_REP| 11000| 9000|
Allan |2004-08-01 00:00:00.000|SA_REP| 9000| 10000|
Peter |2005-01-30 00:00:00.000|SA_REP| 10000| 8000|
Lindsey |2005-03-10 00:00:00.000|SA_REP| 8000| 11500|
Lisa |2005-03-11 00:00:00.000|SA_REP| 11500| 8800|
Alyssa |2005-03-19 00:00:00.000|SA_REP| 8800| 9500|
David |2005-03-24 00:00:00.000|SA_REP| 9500| 9000|
...
'Oracle > SQL' 카테고리의 다른 글
| [SQL] 계층형 쿼리 ( CONNECT BY ) (0) | 2024.03.05 |
|---|---|
| [SQL] 윈도우 함수(Window Function)의 종류(4)- 비율 관련 함수(CUME_DIST, PERCENT_RANK, NTILE, RATIO_TO_REPORT) (1) | 2023.04.18 |
| [SQL] 윈도우 함수(Window Function)의 종류(2) - 집계 관련 함수(SUM, MAX, MIN, AVG, COUNT) (0) | 2023.04.13 |
| [SQL] 윈도우 함수(Window Function)의 종류(1) - 순위 관련 함수(RANK, DENSE_RANK, ROW_NUMBER) (1) | 2023.04.05 |
| [SQL] NULL 처리 (0) | 2023.04.03 |