본문 바로가기

SQL

윈도우함수(WINDOW FUNCTION) 총정리, 순위함수와 분석함수

SQL의 윈도우 함수란 행과 행 간을 비교, 연산, 정의하기 위한 함수이다. 분석함수 또는 순위함수라고 하기도 한다. 다른 함수들처럼 중첩해서 사용할 수는 없지만 서브쿼리에서는 사용가능하다.

 

WINDOW FUNCTION 기본 문법

 

윈도우 함수에는 OVER 문구가 필수로 들어간다.

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

 

WINDOW FUNCTION 종류

구분 함수 비교
순위 함수 RANK, DENSE_RANK, ROW_NUMBER  
일반 집계 함수 SUM, MAX, MIN, AVG, COUNT SQL서버에서는 OVER 절 내에서
ORDER BY 지원하지 않음
그룹 내 행 순서 함수 FIRST_VALUE, LAST_VALUE, LAG, LEAD SQL서버에서는 지원하지 않음
그룹 내 비율 함수 RATIO_TO_REPROT, PERCENT_RANK, CUME_DIST, NTILE NTILE 제외 SQL서버에서는 지원하지 않음

 

 

1. 순위 함수

 

1) RANK

 

ORDER BY를 포함한 쿼리문에서 특정 컬럼의 순위를 구하는 함수이다. PARTITION 내에서 순위를 구할 수도 있고 전체 데이터에 대한 순위를 구할 수도 있다. 동일한 값에 대해서는 같은 순위를 부여하며 중간 순위를 비운다.

 

예를 들어 동일한 값이 있는 경우 순위는 1,1,3,4,4,6 이런식인 셈

 

SELECT JOB, ENAME, SAL, 
       RANK() OVER (PARTITION BY JOB ORDER BY SAL DESC) JOB_RANK 
  FROM EMP;

JOB       ENAME             SAL   JOB_RANK
--------- ---------- ---------- ----------
ANALYST   FORD             3000          1
ANALYST   SCOTT            3000          1
CLERK     MILLER           1300          1
CLERK     ADAMS            1300          1
CLERK     JAMES             950          3
CLERK     SMITH             800          4

 

2) DENSE_RANK

RANK와 작동법은 동일, 동일한 값에 대해서는 같은 순위를 부여하고 중간 순위를 비우지 않는다. 동일한 값이 있는 경우 순위는 1,1,2,3,3,4 이런 식

 

SELECT JOB, ENAME, SAL, 
       DENSE_RANK() OVER (PARTITION BY JOB ORDER BY SAL DESC) JOB_RANK 
  FROM EMP;

JOB       ENAME             SAL   JOB_RANK
--------- ---------- ---------- ----------
ANALYST   FORD             3000          1
ANALYST   SCOTT            3000          1
CLERK     MILLER           1300          1
CLERK     ADAMS            1300          1
CLERK     JAMES             950          2
CLERK     SMITH             800          3

 

 

3) ROW_NUMBER

RANK, DENSE_RANK는 동일한 값에 대해 동일 순위를 부여하지만 ROW_NUMBER은 동일한 값이어도 고유한 순위를 부여한다.

 

SELECT JOB, ENAME, SAL, 
       ROW_NUMBER() OVER (PARTITION BY JOB ORDER BY SAL DESC) JOB_RANK 
  FROM EMP;

JOB       ENAME             SAL   JOB_RANK
--------- ---------- ---------- ----------
ANALYST   FORD             3000          1
ANALYST   SCOTT            3000          2
CLERK     MILLER           1300          1
CLERK     ADAMS            1300          2
CLERK     JAMES             950          3
CLERK     SMITH             800          4

 

 

2. 일반 집계 함수

SUM: 합계

MAX: 최대값

MIN: 최소값

AVG: 평균

COUNT: 조건에 해당하는 컬럼 숫자 출력

 

 

3. 그룹 내 행 순서 함수

 

1) FIRST_VALUE

파티션별 윈도우에서 가장 먼저 나온 값을 구한다. 공동 등수를 인정하지 않고 처음 나온 행만 가져오며 MIN함수를 쓰는 것과 결과가 동일하다.

 

2) LAST_VALUE

파티션별 윈도우에서 가장 마지막에 나온 값을 구한다. 공동 등수를 인정하지 않고 마지막에 나온 행만 가져오며 MAX함수를 쓰는 것과 결과가 동일하다.

 

3) LAG

이전 몇 번째 행의 값을 가져오는 함수이다. 인자를 최대 3개까지 가진다.

두번째 인자는 몇 번째 앞의 행을 가져올지 결정하는 것이며 DEFAULT값은 1이다. 세번째 인자는 가져올 행이 없을 경우 DEFAULT값을 지정해주는 것으로 NVL이나 ISNULL함수의 기능과 동일하다.

 

SELECT ENAME, HIREDATE, SAL
     , LAG(SAL) OVER (ORDER BY HIREDATE) as PREV_SAL 
  FROM EMP 
 WHERE JOB = 'SALESMAN';

ENAME      HIREDATE         SAL   PREV_SAL
---------- --------- ---------- ----------
ALLEN      20-FEB-81       1600
WARD       22-FEB-81       1250       1600
TURNER     08-SEP-81       1500       1250
MARTIN     28-SEP-81       1250       1500

--HIREDATE를 기준으로 정렬하고 본인보다 입사일자가 하나 더 앞선 사원의 급여를 출력

SELECT ENAME, HIREDATE, SAL
     , LAG(SAL, 2, 0) OVER (ORDER BY HIREDATE) as PREV_SAL 
  FROM EMP 
 WHERE JOB = 'SALESMAN' ;

ENAME      HIREDATE         SAL   PREV_SAL
---------- --------- ---------- ----------
ALLEN      20-FEB-81       1600          0
WARD       22-FEB-81       1250          0
TURNER     08-SEP-81       1500       1600
MARTIN     28-SEP-81       1250       1250

--HIREDATE를 기준으로 정렬하고 본인보다 입사일자가 두 개 더 앞선 사원의 급여를 출력
--두 개 더 앞선 사원이 없을 경우 0을 출력

 

4) LEAD

이후 몇 번째 행의 값을 가져오는 함수로 LAG와 마찬가지로 인자를 최대 3개까지 갖는다.

SELECT ENAME, HIREDATE
     , LEAD(HIREDATE, 1) OVER (ORDER BY HIREDATE) as "NEXTHIRED" 
  FROM EMP;

ENAME      HIREDATE  NEXTHIRED
---------- --------- ---------
SMITH      17-DEC-80 20-FEB-81
ALLEN      20-FEB-81 22-FEB-81
WARD       22-FEB-81 02-APR-81
JONES      02-APR-81 01-MAY-81
BLAKE      01-MAY-81 09-JUN-81
CLARK      09-JUN-81

--HIREDATE를 기준으로 정렬하고 본인보다 HIREDATE가 하나 더 뒤인 날짜를 출력
--없는 경우 NULL

 

 

4. 그룹 내 비율 함수

 

1) RATIO_TO_REPORT

파티션 내 전체 SUM값에 대한 행별 컬럼 값의 백분율을 소수점으로 출력한다. 결과값은 0~1 사이이며 개별 비율의 합을 구하면 1이다.

 

SELECT ENAME, SAL
     , ROUND(RATIO_TO_REPORT(SAL) OVER (), 2) as R_R 
  FROM EMP 
 WHERE JOB = 'SALESMAN'; 

ENAME             SAL        R_R
---------- ---------- ----------
ALLEN            1600        .29
WARD             1250        .22
MARTIN           1250        .22
TURNER           1500        .27

--전체 급여에서 각각이 차지하는 비율 출력

 

2) PERCENT_RANK

파티션별로 가장 먼저 나오는 값을 0, 가장 마지막에 나오는 값을 1 해서 순서별 백분율 출력한다. 구간을 나누어 백분율로 표시한다.

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         .5
        10 MILLER           1300          1
        20 SCOTT            3000          0
        20 FORD             3000          0
        20 JONES            2975         .5
        20 ADAMS            1100        .75
        20 SMITH             800          1
        30 BLAKE            2850          0
        30 ALLEN            1600         .2
        30 TURNER           1500         .4
        30 MARTIN           1250         .6
        30 WARD             1250         .6
        30 JAMES             950          1
        
        --DEPTNO를 기준으로 파티셔닝해서 순서별 백분율 출력

 

3) CUME_DIST

파티션별 전체건수에서 현재 행보다 작거나 같은 건수에 대한 누적백분율을구한다.

 

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 .333333333
        10 CLARK            2450 .666666667
        10 MILLER           1300          1
        20 SCOTT            3000         .4
        20 FORD             3000         .4
        20 JONES            2975         .6
        20 ADAMS            1100         .8
        20 SMITH             800          1
        30 BLAKE            2850 .166666667
        30 ALLEN            1600 .333333333
        30 TURNER           1500         .5
        30 MARTIN           1250 .833333333
        30 WARD             1250 .833333333
        30 JAMES             950          1
        
  --DEPTNO를 기준으로 파티셔닝해서 누적 백분율 출력

 

4) NTILE

파티션별 전체 건수를 ARGUMENT값으로 N등분한 결과를 출력한다.

SELECT ENAME, SAL
     , NTILE(4) OVER (ORDER BY SAL DESC) as QUAR_TILE 
  FROM EMP ;

ENAME             SAL  QUAR_TILE
---------- ---------- ----------
KING             5000          1
FORD             3000          1
SCOTT            3000          1
JONES            2975          1
BLAKE            2850          2
CLARK            2450          2
ALLEN            1600          2
TURNER           1500          2
MILLER           1300          3
WARD             1250          3
MARTIN           1250          3
ADAMS            1100          4
JAMES             950          4
SMITH             800          4

--전체건수를 ARGUMENT값(여기서는 4)으로 N등분한 결과 출력
--14를 4로 나누면 몫이 3 나머지가 2, 나머지2는 앞의 조부터 할당되기 때문에 4,4,3,3으로 나눔