[ SQLD : II. SQL 기본 및 활용] 2-6. 윈도우(Window) 함수

문지은·2023년 6월 7일
0

SQLD

목록 보기
25/30
post-thumbnail

[SQLD 시험 대비] 2과목. SQL 기본 및 활용 : 2장. SQL 활용 - 6. 윈도우(Window) 함수

윈도우(Window) 함수 개요

  • 행과 행간의 관계를 쉽게 정의하기 위해 만든 함수
  • 윈도우 함수를 활용하면 복잡한 프로그램을 하나의 SQL 문장으로 쉽게 해결할 수 있다.
  • WINDOW 함수는 기존에 사용하던 집계 함수도 있고, 새로이 WINDOW 함수 전용으로 만들어진 기능도 있다.
  • WINDOW 함수는 다른 함수와는 달리 중첩(NEST)해서 사용하지는 못하지만, 서브쿼리에서는 사용할 수 있다.

WINDOW FUNCTION 종류

WINDOW FUNCTION의 종류는 크게 다섯 개의 그룹으로 분류할 수 있는데 벤더별로 지원하는 함수에는 차이가 있다.

  • 그룹 내 순위(RANK) 관련 함수
    • RANK, DENSE_RANK, ROW_NUMBER 함수가 있다.
    • ANSI/ISO SQL 표준과 Oracle, SQL Server 등 대부분의 DBMS에서 지원하고 있다.
  • 그룹 내 집계(AGGREGATE) 관련 함수
    • 일반적으로 많이 사용하는 SUM, MAX, MIN, AVG, COUNT 함수
    • ANSI/ISO SQL 표준과 Oracle, SQL Server 등 대부분의 DBMS에서 지원
  • 그룹 내 행 순서 관련 함수
    • FIRST_VALUE, LAST_VALUE, LAG, LEAD 함수 가 있다.
    • Oracle에서만 지원되는 함수
  • 그룹 내 비율 관련 함수
    • CUME_DIST, PERCENT_RANK, NTILE, RATIO_TO_REPORT 함수
    • CUME_DIST, PERCENT_RANK 함수는 ANSI/ISO SQL 표준과 Oracle DBMS에서 지원
    • NTILE 함수는 ANSI/ISO SQL 표준에는 없지만, Oracle, SQL Server에서 지원
    • RATIO_TO_REPORT 함수는 Oracle에서만 지원되는 함수
  • 선형 분석을 포함한 통계 분석 관련 함수

WINDOW FUNCTION SYNTAX

  • WINDOW 함수에는 OVER 문구가 키워드로 필수 포함된다.
SELECT WINDOW_FUNCTION (ARGUMENTS) OVER
( [PARTITION BY 칼럼] [ORDER BY] [WINDOWING 절] )
FROM 테이블 명;
  • WINDOW_FUNCTION
    • 기존에 사용하던 함수도 있고, 새롭게 WINDOW 함수용으로 추가된 함수도 있다.
  • ARGUMENTS (인수)
    • 함수에 따라 0 ~ N개의 인수가 지정될 수 있다.
  • PARTITION BY 절
    • 전체 집합을 기준에 의해 소그룹으로 나눌 수 있다.
  • ORDER BY 절
    • 어떤 항목에 대해 순위를 지정할 지 ORDER BY 절을 기술한다.
  • WINDOWING 절
    • WINDOWING 절은 함수의 대상이 되는 행 기준의 범위를 강력하게 지정할 수 있다.
    • ROWS 는 물리적인 결과 행의 수를, RANGE는 논리적인 값에 의한 범위를 나타내는데, 둘 중의 하나를 선택해서 사용할 수 있다.
    • 다만, WINDOWING 절은 SQL Server에서는 지원하지 않는다.

그룹 내 순위 함수

RANK 함수

  • RANK 함수는 ORDER BY를 포함한 QUERY 문에서 특정 항목(칼럼)에 대한 순위를 구하는 함수이다.
  • 이때 특정 범위(PARTITION) 내에서 순위를 구할 수도 있고 전체 데이터에 대한 순위를 구할 수도 있다.
  • 동일한 값에 대해서는 동일한 순위를 부여한다.

예제

  • 사원 데이터에서 급여가 높은 순서와 JOB 별로 급여가 높은 순서를 같이 출력한다.
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;

  • 업무 구분이 없는 ALL_RANK 칼럼에서 FORD와 SCOTT, WARD와 MARTIN은 동일한 SALARY이므로 같은 순위가 부여되었다.
  • 업무를 PARTITION으로 구분한 JOB_RANK의 경우 같은 업무 내 범위에서만 순위를 부여했다.

DENSE_RANK 함수

  • 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;

  • FORD와 SCOTT, WARD와 MARTIN은 동일한 SALARY이므로 RANK와 DENSE_RANK 칼럼에서 모두 같은 순위를 부여한다.
  • RANK와 DENSE_RANK의 차이를 알 수 있는 데이터
    • FORD와 SCOTT의 다음 순위인 JONES의 경우 RANK는 4등으로 DENSE_RANK는 3등으로 표시되어 있다.
    • WARD와 MARTIN의 다음 순위인 ADAMS의 경우 RANK는 12등으로 DENSE_RANK 는 10등으로 표시되어 있다.

ROW_NUMBER 함수

  • 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;

  • FORD와 SCOTT, WARD와 MARTIN은 동일한 SALARY이므로 RANK는 같은 순위를 부여했지만, ROW_NUMBER의 경우 동일한 순위를 배제하기 위해 유니크한 순위를 정했다.

일반 집계 함수

SUM 함수

  • SUM 함수를 이용해 파티션별 윈도우의 합을 구할 수 있다.

예제

  • 사원들의 급여와 같은 매니저를 두고 있는 사원들의 SALARY 합을 구한다.
    • 이 때 PARTITION BY MGR 구문을 통해 매니저별로 데이터를 파티션화 한다.
SELECT MGR, ENAME, SAL, SUM(SAL) OVER (PARTITION BY MGR) MGR_SUM
FROM EMP;
  • OVER 절 내에 ORDER BY 절을 추가해 파티션 내 데이터를 정렬하고 이전 SALARY 데이터까지의 누적값을 출력해보자.
SELECT MGR, ENAME, SAL,
	   SUM(SAL) OVER (PARTITION BY MGR UNBOUNDED PRECEDING)
       as MGR_SUM 
FROM EMP

// RANGE UNBOUNDED PRECEDING 
// : 현재 행을 기준으로 파티션 내의 첫 번째 행까지의 범위를 지정한다.

MAX 함수

  • MAX 함수를 이용해 파티션별 윈도우의 최대값을 구할 수 있다.

예제

  • 사원들의 급여와 같은 매니저를 두고 있는 사원들의 SALARY 중 최대값을 같이 구한다.
  • 실행 결과를 확인하면 파티션 내의 최대값을 파티션 내 모든 행에서 MGR_MAX라는 칼럼 값으로 가질 수 있다.
SELECT MGR, ENAME, SAL, MAX(SAL) OVER (PARTITION BY MGR) as MGR_MAX 
FROM EMP;
  • 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 ;

MIN 함수

  • MIN 함수를 이용해 파티션별 윈도우의 최소값을 구할 수 있다.

예제

  • 사원들의 급여와 같은 매니저를 두고 있는 사원들을 입사일자를 기준으로 정렬하고, SALARY 최소값을 같이 구한다.
SELECT MGR, ENAME, HIREDATE, SAL,
       MIN(SAL) OVER(PARTITION BY MGR ORDER BY HIREDATE) as MGR_MIN 
FROM EMP;

AVG 함수

  • AVG 함수와 파티션별 ROWS 윈도우를 이용해 원하는 조건에 맞는 데이터에 대한 통계값을 구할 수 있다.

예제

  • EMP 테이블에서 같은 매니저를 두고 있는 사원들의 평균 SALARY를 구하는데, 조건은 같은 매니저 내에서 자기 바로 앞의 사번과 바로 뒤의 사번인 직원만을 대상으로 한다.
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 :
// 현재 행을 기준으로 파티션 내에서 앞의 한 건, 현재 행, 뒤의 한 건을 범위로 지정한다.

COUNT 함수

  • COUNT 함수와 파티션별 ROWS 윈도우를 이용해 원하는 조건에 맞는 데이터에 대한 통계 값을 구할 수 있다.

예제

  • 사원들을 급여 기준으로 정렬하고, 본인의 급여보다 50 이하가 적거나 150 이하로 많은 급여를 받는 인원수를 출력하라.
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의 범위 내에 포함된 모든 행이 대상이 된다. 

그룹 내 행 순서 함수

FIRST_VALUE 함수

  • 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;

// RANGE UNBOUNDED PRECEDING :
// 현재 행을 기준으로 파티션 내의 첫 번째 행까지의 범위를 지정한다.
  • 같은 값을 가진 FIRST_VALUE를 처리하기 위해 ORDER BY 정렬 조건을 추가한다.
SELECT DEPTNO, ENAME, SAL,
       FIRST_VALUE(ENAME) OVER
       (PARTITION BY DEPTNO ORDER BY SAL DESC, ENAME ASC
       ROWS UNBOUNDED PRECEDING) as RICH_EMP 
FROM EMP;

LAST_VALUE 함수

  • 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: 
// 현재 행을 포함해서 파티션 내의 마지막 행까지의 범위를 지정한다.

LAG 함수

  • LAG 함수를 이용해 파티션별 윈도우에서 이전 몇 번째 행의 값을 가져올 수 있다.
  • SQL Server에서는 지원하지 않는 함수이다.
  • LAG 함수는 3개의 ARGUMENTS 까지 사용할 수 있다.
    • 두 번째 인자는 몇 번째 앞의 행을 가져올지 결정하는 것이고 (DEFAULT 1),
    • 세 번째 인자는 예를 들어 파티션의 첫 번째 행의 경우 가져올 데이터가 없어 NULL 값이 들어오는데 이 경우 다른 값으로 바꾸어 줄 수 있다.
      • 결과적으로 NVL이나 ISNULL 기능과 같다.

예제

  • 직원들을 입사일자가 빠른 기준으로 정렬을 하고, 본인보다 입사일자가 한 명 앞선 사원의 급여를 본인의 급여와 함께 출력한다.
SELECT ENAME, HIREDATE, SAL, LAG(SAL) OVER (ORDER BY HIREDATE) as PREV_SAL 
FROM EMP
WHERE JOB = 'SALESMAN' ;

LEAD 함수

  • LEAD 함수를 이용해 파티션별 윈도우에서 이후 몇 번째 행의 값을 가져올 수 있다.
  • SQL Server에서는 지원하지 않는 함수이다.
  • LEAD 함수는 3개의 ARGUMENTS 까지 사용할 수 있다.
    • 두 번째 인자는 몇 번째 후의 행을 가져올지 결정하는 것이고 (DEFAULT 1),
    • 세 번째 인자는 예를 들어 파티션의 마지막 행의 경우 가져올 데이터가 없어 NULL 값이 들어오는데 이 경우 다른 값으로 바꾸어 줄 수 있다.

예제

  • 직원들을 입사일자가 빠른 기준으로 정렬을 하고, 바로 다음에 입사한 인력의 입사 일자를 함께 출력한다.
SELECT ENAME, HIREDATE,
	   LEAD (HIREDATE, 1) OVER (ORDER BY HIREDATE) as "NEXTHIRED" 
FROM EMP;

그룹 내 비율 함수

RATIO_TO_REPORT 함수

  • RATIO_TO_REPORT 함수를 이용해 파티션 내 전체 SUM(칼럼)값에 대한 행별 칼럼 값의 백분율을 소수점으로 구할 수 있다.
  • 결과 값은 >0 &<= 1 의 범위를 가진다. 그리고 개별 RATIO의 합을 구하면 1이 된다.
  • SQL Server에서는 지원하지 않는 함수이다.

예제

  • JOB이 SALESMAN인 사원들을 대상으로 전체 급여에서 본인이 차지하는 비율을 출력한다.
SELECT ENAME, SAL, ROUND(RATIO_TO_REPORT(SAL) OVER (), 2) as R_R 
FROM EMP
WHERE JOB = 'SALESMAN';

PERCENT_RANK 함수

  • PERCENT_RANK 함수를 이용해 파티션별 윈도우에서 제일 먼저 나오는 것을 0으로, 제일 늦게 나오는 것을 1로 하여, 값이 아닌 행의 순서별 백분율을 구한다.
  • 결과 값은 >= 0 &<= 1 의 범위를 가진다.
  • SQL Server에서는 지원하지 않는 함수이다.

예제

  • 같은 부서 소속 사원들의 집합에서 본인의 급여가 순서상 몇 번째 위치쯤에 있는지 0과 1 사이의 값으로 출력한다.
SELECT DEPTNO, ENAME, SAL,
       PERCENT_RANK() OVER (PARTITION BY DEPTNO ORDER BY SAL DESC) as P_R 
FROM EMP;

CUME_DIST 함수

  • CUME_DIST 함수를 이용해 파티션별 윈도우의 전체건수에서 현재 행보다 작거나 같은 건 수에 대한 누적백분율을 구한다.
  • 결과 값은 >0 &<= 1 의 범위를 가진다.
  • SQL Server에서는 지원하지 않는 함수이다.

예제

  • 같은 부서 소속 사원들의 집합에서 본인의 급여가 누적 순서상 몇 번째 위치쯤에 있 는지 0과 1 사이의 값으로 출력한다.
SELECT DEPTNO, ENAME, SAL,
CUME_DIST() OVER (PARTITION BY DEPTNO ORDER BY SAL DESC) as CUME_DIST 
FROM EMP;

NTILE 함수

  • NTILE 함수를 이용해 파티션별 전체 건수를 ARGUMENT 값으로 N 등분한 결과를 구할 수 있다.

예제

  • 전체 사원을 급여가 높은 순서로 정렬하고, 급여를 기준으로 4개의 그룹으로 분류한다.
SELECT ENAME, SAL, NTILE(4) OVER (ORDER BY SAL DESC) as QUAR_TILE 
FROM EMP;

profile
코드로 꿈을 펼치는 개발자의 이야기, 노력과 열정이 가득한 곳 🌈

1개의 댓글

comment-user-thumbnail
2023년 6월 9일

감사합니다.

답글 달기