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칸 뒤
SUM
sum 함수를 사용하여 같은 매니저를 둔 사원들의 급여의 합을 구하는 예제
SELECT MANAGER_ID, FIRST_NAME , SALARY ,
SUM(SALARY) OVER (PARTITION BY MANAGER_ID) MGR_SUM
FROM EMPLOYEES e ;
MANAGER_ID|FIRST_NAME |SALARY|MGR_SUM|
----------+-----------+------+-------+
100|Neena | 17000| 155400|
100|Lex | 17000| 155400|
100|Den | 11000| 155400|
100|Matthew | 8000| 155400|
100|Adam | 8200| 155400|
100|Payam | 7900| 155400|
100|Shanta | 6500| 155400|
100|Kevin | 5800| 155400|
100|John | 14000| 155400|
100|Karen | 13500| 155400|
100|Alberto | 12000| 155400|
100|Gerald | 11000| 155400|
100|Eleni | 10500| 155400|
100|Michael | 13000| 155400|
101|Jennifer | 4400| 44916|
101|Susan | 6500| 44916|
101|Nancy | 12008| 44916|
...
ROWS UNBOUNDED PRECEDING 라는 윈도우 절을 사용하여 이전 급여에 새로운 급여를 차례로 더하는 누적 값을 보여주는 예제
ROWS UNBOUNDED PRECEDING : 현재 행을 기준으로 파티션 내의 첫 번째 행까지 범위를 지정한다.
(WINDOWING 절은 나중에 따로 자세히 다루도록 함)
SELECT MANAGER_ID, FIRST_NAME , SALARY ,
SUM(SALARY) OVER (PARTITION BY MANAGER_ID ORDER BY SALARY ROWS UNBOUNDED PRECEDING ) MGR_SUM
FROM EMPLOYEES e ;
MANAGER_ID|FIRST_NAME |SALARY|MGR_SUM|
----------+-----------+------+-------+
100|Kevin | 5800| 5800|
100|Shanta | 6500| 12300|
100|Payam | 7900| 20200|
100|Matthew | 8000| 28200|
100|Adam | 8200| 36400|
100|Eleni | 10500| 46900|
100|Den | 11000| 57900|
100|Gerald | 11000| 68900|
100|Alberto | 12000| 80900|
100|Michael | 13000| 93900|
100|Karen | 13500| 107400|
100|John | 14000| 121400|
100|Lex | 17000| 138400|
100|Neena | 17000| 155400| --> 위의 MGR_SUM 컬럼과 같은 값이 되었다.
101|Jennifer | 4400| 4400|
101|Susan | 6500| 10900|
101|Hermann | 10000| 20900|
101|Shelley | 12008| 32908|
101|Nancy | 12008| 44916| --> 위의 MGR_SUM 컬럼과 같은 값이 되었다.
102|Alexander | 9000| 9000|
...
MAX
같은 매니저를 둔 사원들중 가장 큰 급여를 보여주는 예제
SELECT MANAGER_ID, FIRST_NAME , SALARY ,
MAX(SALARY) OVER (PARTITION BY MANAGER_ID) SAL_MAX
FROM EMPLOYEES e ;
MANAGER_ID|FIRST_NAME |SALARY|SAL_MAX|
----------+-----------+------+-------+
100|Neena | 17000| 17000|
100|Lex | 17000| 17000|
100|Den | 11000| 17000|
100|Matthew | 8000| 17000|
100|Adam | 8200| 17000|
100|Payam | 7900| 17000|
100|Shanta | 6500| 17000|
100|Kevin | 5800| 17000|
100|John | 14000| 17000|
100|Karen | 13500| 17000|
100|Alberto | 12000| 17000|
100|Gerald | 11000| 17000|
100|Eleni | 10500| 17000|
100|Michael | 13000| 17000|
101|Jennifer | 4400| 12008|
101|Susan | 6500| 12008|
101|Nancy | 12008| 12008|
101|Shelley | 12008| 12008|
101|Hermann | 10000| 12008|
102|Alexander | 9000| 9000|
인라인 뷰를 사용해 같은 매니저를 둔 사원들중 가장 높은 급여를 받는 사원들을 조회하는 예제
SELECT MANAGER_ID, FIRST_NAME , SALARY
FROM (
SELECT MANAGER_ID, FIRST_NAME , SALARY ,
MAX(SALARY) OVER (PARTITION BY MANAGER_ID) SAL_MAX
FROM EMPLOYEES e )
WHERE SALARY = SAL_MAX
ORDER BY MANAGER_ID;
MANAGER_ID|FIRST_NAME|SALARY|
----------+----------+------+
100|Neena | 17000|
100|Lex | 17000|
101|Nancy | 12008|
101|Shelley | 12008|
102|Alexander | 9000|
103|Bruce | 6000|
...
MIN
같은 매니저를 둔 사원들 중 가장 적은 급여를 보여주는 예제
SELECT MANAGER_ID, FIRST_NAME , HIRE_DATE, SALARY ,
MIN(SALARY) OVER (PARTITION BY MANAGER_ID ) SAL_MIN
FROM EMPLOYEES e ;
MANAGER_ID|FIRST_NAME |HIRE_DATE |SALARY|SAL_MIN|
----------+-----------+-----------------------+------+-------+
100|Neena |2005-09-21 00:00:00.000| 17000| 5800|
100|Lex |2001-01-13 00:00:00.000| 17000| 5800|
100|Den |2002-12-07 00:00:00.000| 11000| 5800|
100|Matthew |2004-07-18 00:00:00.000| 8000| 5800|
100|Adam |2005-04-10 00:00:00.000| 8200| 5800|
100|Payam |2003-05-01 00:00:00.000| 7900| 5800|
100|Shanta |2005-10-10 00:00:00.000| 6500| 5800|
100|Kevin |2007-11-16 00:00:00.000| 5800| 5800|
100|John |2004-10-01 00:00:00.000| 14000| 5800|
100|Karen |2005-01-05 00:00:00.000| 13500| 5800|
100|Alberto |2005-03-10 00:00:00.000| 12000| 5800|
100|Gerald |2007-10-15 00:00:00.000| 11000| 5800|
100|Eleni |2008-01-29 00:00:00.000| 10500| 5800|
100|Michael |2004-02-17 00:00:00.000| 13000| 5800|
101|Jennifer |2003-09-17 00:00:00.000| 4400| 4400|
101|Susan |2002-06-07 00:00:00.000| 6500| 4400|
101|Nancy |2002-08-17 00:00:00.000| 12008| 4400|
101|Shelley |2002-06-07 00:00:00.000| 12008| 4400|
101|Hermann |2002-06-07 00:00:00.000| 10000| 4400|
102|Alexander |2006-01-03 00:00:00.000| 9000| 9000|
...
같은 매니저를 둔 사원중 입사일을 기준으로 정렬되어(ASC) 해당 로우의 입사일자를 포함 이전 날짜중에 가장 적은 급여를 보여주는 예제
SELECT MANAGER_ID, FIRST_NAME , HIRE_DATE, SALARY ,
MIN(SALARY) OVER (PARTITION BY MANAGER_ID ORDER BY HIRE_DATE) SAL_MIN
FROM EMPLOYEES e ;
MANAGER_ID|FIRST_NAME |HIRE_DATE |SALARY|SAL_MIN|
----------+-----------+-----------------------+------+-------+
100|Lex |2001-01-13 00:00:00.000| 17000| 17000|
100|Den |2002-12-07 00:00:00.000| 11000| 11000|
100|Payam |2003-05-01 00:00:00.000| 7900| 7900|
100|Michael |2004-02-17 00:00:00.000| 13000| 7900|
100|Matthew |2004-07-18 00:00:00.000| 8000| 7900|
100|John |2004-10-01 00:00:00.000| 14000| 7900|
100|Karen |2005-01-05 00:00:00.000| 13500| 7900|
100|Alberto |2005-03-10 00:00:00.000| 12000| 7900|
100|Adam |2005-04-10 00:00:00.000| 8200| 7900|
100|Neena |2005-09-21 00:00:00.000| 17000| 7900|
100|Shanta |2005-10-10 00:00:00.000| 6500| 6500|
100|Gerald |2007-10-15 00:00:00.000| 11000| 6500|
100|Kevin |2007-11-16 00:00:00.000| 5800| 5800|
100|Eleni |2008-01-29 00:00:00.000| 10500| 5800|
101|Hermann |2002-06-07 00:00:00.000| 10000| 6500|
101|Shelley |2002-06-07 00:00:00.000| 12008| 6500|
101|Susan |2002-06-07 00:00:00.000| 6500| 6500|
101|Nancy |2002-08-17 00:00:00.000| 12008| 6500|
101|Jennifer |2003-09-17 00:00:00.000| 4400| 4400|
102|Alexander |2006-01-03 00:00:00.000| 9000| 9000|
...
AVG
같은 매니저를 둔 사원들의 급여의 평균을 구하는 예제 ( 반올림 )
SELECT MANAGER_ID, FIRST_NAME, SALARY ,
ROUND( AVG(SALARY) OVER (PARTITION BY MANAGER_ID )) SAL_AVG
FROM EMPLOYEES e ;
MANAGER_ID|FIRST_NAME |SALARY|SAL_AVG|
----------+-----------+------+-------+
100|Neena | 17000| 11100|
100|Lex | 17000| 11100|
100|Den | 11000| 11100|
100|Matthew | 8000| 11100|
100|Adam | 8200| 11100|
100|Payam | 7900| 11100|
100|Shanta | 6500| 11100|
100|Kevin | 5800| 11100|
100|John | 14000| 11100|
100|Karen | 13500| 11100|
100|Alberto | 12000| 11100|
100|Gerald | 11000| 11100|
100|Eleni | 10500| 11100|
100|Michael | 13000| 11100|
101|Jennifer | 4400| 8983|
101|Susan | 6500| 8983|
101|Nancy | 12008| 8983|
101|Shelley | 12008| 8983|
101|Hermann | 10000| 8983|
102|Alexander | 9000| 9000|
같은 매니저를 둔 사원들을 입사일로 정렬 하여 자기 자신 포함 이전 로우 하나와 다음 로우 하나의 ( 3 rows) 평균을 구하는 예제
SELECT MANAGER_ID, FIRST_NAME , HIRE_DATE, SALARY ,
ROUND (AVG(SALARY) OVER (PARTITION BY MANAGER_ID ORDER BY HIRE_DATE ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING )) SAL_AVG
FROM EMPLOYEES e ;
MANAGER_ID|FIRST_NAME |HIRE_DATE |SALARY|SAL_AVG|
----------+-----------+-----------------------+------+-------+
100|Lex |2001-01-13 00:00:00.000| 17000| 14000|
100|Den |2002-12-07 00:00:00.000| 11000| 11967|
100|Payam |2003-05-01 00:00:00.000| 7900| 10633|
100|Michael |2004-02-17 00:00:00.000| 13000| 9633|
100|Matthew |2004-07-18 00:00:00.000| 8000| 11667|
100|John |2004-10-01 00:00:00.000| 14000| 11833|
100|Karen |2005-01-05 00:00:00.000| 13500| 13167|
100|Alberto |2005-03-10 00:00:00.000| 12000| 11233|
100|Adam |2005-04-10 00:00:00.000| 8200| 12400|
100|Neena |2005-09-21 00:00:00.000| 17000| 10567|
100|Shanta |2005-10-10 00:00:00.000| 6500| 11500|
100|Gerald |2007-10-15 00:00:00.000| 11000| 7767|
100|Kevin |2007-11-16 00:00:00.000| 5800| 9100|
100|Eleni |2008-01-29 00:00:00.000| 10500| 8150|
101|Hermann |2002-06-07 00:00:00.000| 10000| 11004|
101|Shelley |2002-06-07 00:00:00.000| 12008| 9503|
101|Susan |2002-06-07 00:00:00.000| 6500| 10172|
101|Nancy |2002-08-17 00:00:00.000| 12008| 7636|
101|Jennifer |2003-09-17 00:00:00.000| 4400| 8204|
102|Alexander |2006-01-03 00:00:00.000| 9000| 9000|
103|David |2005-06-25 00:00:00.000| 4800| 4800|
103|Valli |2006-02-05 00:00:00.000| 4800| 4600|
103|Diana |2007-02-07 00:00:00.000| 4200| 5000|
103|Bruce |2007-05-21 00:00:00.000| 6000| 5100|
...
COUNT
같은 매니저를 둔 사원들의 수를 구하는 예제
SELECT MANAGER_ID, EMPLOYEE_ID, FIRST_NAME, SALARY ,
count(EMPLOYEE_ID) OVER (PARTITION BY MANAGER_ID ) SAL_CNT
FROM EMPLOYEES e ;
MANAGER_ID|EMPLOYEE_ID|FIRST_NAME |SALARY|SAL_CNT|
----------+-----------+-----------+------+-------+
100| 101|Neena | 17000| 14|
100| 102|Lex | 17000| 14|
100| 114|Den | 11000| 14|
100| 120|Matthew | 8000| 14|
100| 121|Adam | 8200| 14|
100| 122|Payam | 7900| 14|
100| 123|Shanta | 6500| 14|
100| 124|Kevin | 5800| 14|
100| 145|John | 14000| 14|
100| 146|Karen | 13500| 14|
100| 147|Alberto | 12000| 14|
100| 148|Gerald | 11000| 14|
100| 149|Eleni | 10500| 14|
100| 201|Michael | 13000| 14|
101| 200|Jennifer | 4400| 5|
101| 203|Susan | 6500| 5|
101| 108|Nancy | 12008| 5|
101| 205|Shelley | 12008| 5|
101| 204|Hermann | 10000| 5|
102| 103|Alexander | 9000| 1|
...
사원 급여 순으로 정렬 후 본인 월급의 -50 이하 부터 +200 이상인 월급을 가진 로우수(해당 로우 포함)를 구하는 예제
SELECT ENAME, SAL,
COUNT(*) OVER (ORDER BY SAL
RANGE BETWEEN 50 PRECEDING AND 150 FOLLOWING) SIM_CNT
FROM EMP ;
MANAGER_ID|FIRST_NAME |SALARY|SAL_CNT|
----------+-----------+------+-------+
121|TJ | 2100| 3|
120|Steven | 2200| 4|
122|Hazel | 2200| 4|
120|James | 2400| 12|
122|Ki | 2400| 12|
114|Karen | 2500| 12|
121|James | 2500| 12|
123|Joshua | 2500| 12|
124|Peter | 2500| 12|
120|Martha | 2500| 12|
122|Randall | 2500| 12|
114|Guy | 2600| 10|
124|Randall | 2600| 10|
124|Donald | 2600| 10|
124|Douglas | 2600| 10|
120|Irene | 2700| 9|
123|John | 2700| 9|
...
'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)의 종류(3) - 행 순서 관련 함수(FIRST_VALUE, LAST_VALUE, LAG, LEAD) (1) | 2023.04.17 |
| [SQL] 윈도우 함수(Window Function)의 종류(1) - 순위 관련 함수(RANK, DENSE_RANK, ROW_NUMBER) (1) | 2023.04.05 |
| [SQL] NULL 처리 (0) | 2023.04.03 |