본문 바로가기

sqld

2-12) 윈도우 함수

윈도우 함수 (WINDOW FUNCTION)
  • 서로 다른 행의 비교나 연산을 위해 만든 함수
  • 본래 다른 행의 조회는 불가능
  • GROUP BY를 쓰지 않고 그룹 연산 가능
  • LAG, LEAD, SUM, AVG, MIN, MAX, COUNT, RANK

 

** 문법

  • PARTITION BY 절
    • 출력할 총 데이터 수 변화 없이 그룹 연산 수행할 GROUP BY 컬럼
    • GROUP BY는 출력할 총 데이터 수를 변화시키지만 WINDOW FUNCTION에서 PARTITION BY사용하면 그룹화된 데이터를 통한 연산을 총 데이터 수 변화 없이 출력 가능
  • ORDER BY 절
    • RANK의 경우 필수 (정렬 컬럼 및 정렬 순서에 따라 순위 변화)
    • SUM, AVG, MIN, MAX, COUNT 등은 누적값 출력 시 사용
  • ROWS | RANGE BETWEEN A AND B
    • 연산 범위 설정
    • ORDER BY 절 필수

** 순서 중요 ! (ORDER BY를 PARTITION BY 전에 사용 불가)

PARTITION BY → ORDER BY → ROWS | RANGE BETWEEN A AND B

 

예) 그룹 함수 오류 (윈도우 함수가 필요한 이유)

  • 전체를 출력하는 컬럼과 그룹함수 결과는 함께 출력 불가

 

그룹 함수의 형태
  • SUM, COUNT, AVG, MIN, MAX 등
  • OVER 절을 사용하여 윈도우 함수로 사용 가능
  • 반드시 연산할 대상을 그룹함수의 입력값으로 전달

 

** 문법

 

 

1.  SUM OVER()

  • 전체 총 합, 그룹별 총 합 출력 가능

 

예) 각 직원 정보와 함께 급여 총 합 출력

- 각 직원 정보와 그룹함수 결과(급여 총 합)를 동시에 출력 시도 시 에러 발생

 

해결 1) 서브쿼리 사용 (스칼라 서브쿼리)

 

해결 2) 윈도우 함수 사용

  • OVER() 괄호 안에 아무 것도 안 들어가더라도 OVER 기술 필요
  • OVER() 쓰지 않으면 일반 집계 함수이므로 에러

 

2. AVG OVER()

 

3. MIN / MAX OVER()

 

4. COUNT

 

** 모두 SUM과 동일하게 사용

 

윈도우 함수의 연산 범위
  • 집계 연산 시 행의 범위 설정 가능

 

1. ROWS, RANGE 차이

  • ROWS : 값이 같더라도 각 행씩 계산
  • RANGE : 값이 같은 경우 하나의 RANGE로 묶어서 동시 연산 (DEFAULT)

 

2. BETWEEN A AND B

  • A) 시작점 정의
    • CURRENT ROW : 현재 행부터
    • UNBOUNDED PRECEDING : 처음부터 (DEFAULT)
    • N PRECEDING : N 이전부터
  • B) 마지막 시점 정의
    • CURRENT ROW : 현재 행까지 (DEFAULT)
    • UNBOUNDED FOLLOWING : 마지막까지
    • N FOLLOWING : N 이후까지

** A에는 FOLLOWING이 포함될 수 없고, B에는 PRECEDING이 포함될 수 없음

** CURRENT ROW는 둘 다 포함

 

예) RANGE TEST 테이블에서의 범위 설정에 따른 누적합

 

CASE 1) RANGE 범위 (DEFAULT)

  • DEFAULT : RANGE 범위!
  • 값이 같을 경우 같은 범위로 취급하여 동시 연산
  • 값의 중복이 없었다면 SAL 1250 행에서의 SUM은 2850+1250 = 4100이었겠지만, 2850+1250+1250 5350으로 계산됨

 

CASE 2) ROWS 범위 설정 : 각 행 별로 연산 수행

  • BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW : 처음부터 현재 행까지 누적 합

 

CASE 3) BETWEEN A AND B 수정 시

  • BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING : 처음부터 다음 행까지 누적 합
  • N을 변경 시 다음 N개 행까지 누적 합

 

순위 관련 함수

 

1. RANK(순위)

1-1) RANK WITHIN GROUP

  • 특정 값에 대한 순위 확인
  • 윈도우 함수가 아닌 일반 함수

 

** 문법

 

 

예) EMP에서 급여가 3000이면 전체 급여 순위가 얼마인지

  • SAL을 내림차순 정렬한 것에서 3000의 순위 출력

 

2. RANK() OVER()

  • 전체 중 / 특정 그룹 중 값의 순위 확인
  • ORDER BY절 필수
  • 순위를 구할 대상을 ORDER BY 절에 명시 (여러 개 나열 가능)
  • 그룹 내 순위 구할 시 PARTITION BY 절 사용
  • 중복된 값 처리 ≫ 예) 1,2,2,4,4,6으로 랭킹

 

** 문법

 

 

예1) 각 직원의 급여의 전체 순위 (큰 순서대로)

- 직원 정보와 함께 SAL에 대한 순위를 함께 출력

 

예2) 각 직원 이름, 부서 번호, 급여, 부서별 급여 순위 (큰 순서대로)

- 부서별 조건 추가 → PARTITION BY 필요

  • 어떤 기준으로 RANKING할지는 ORDER BY에 나오기 때문에 RANK()의 괄호에 포함할 필요 X

 

3. DENSE_RANK

  • 누적 순위
  • 값이 같을 때 동일한 순위 부여 후 다음 순위가 바로 이어지는 순위 부여 방식
  • 예) 1등이 5명이더라도 그 다음 순위가 2등

 

4. ROW_NUMBER

  • 연속된 행 번호
  • 동일한 순위를 인정하지 않고 단순히 순서대로 나열한 대로의 순서 값 리턴
  • 예) 값이 동일하더라도 1,2,3,4,5,6,7...

 

예) RANK, DENSE_RANK, ROW_NUMBER 비교

 

 

LAG, LEAD
  • 행 순서대로 각각 이전 값(LAG), 이후 값(LEAD) 가져오기
  • ORDER BY 절 필수

 

** 문법

 

 

예) EMP에서 바로 이전 입사자와 급여 비교

  • LAG(SAL, N) → N 생략하고 컬럼만 전달 시 DEFAULT는 1, 이전 행의 SAL 출력

 

** 이전 / 이후 값을 가져올 때 이전 값이 같더라도 항상 행의 순서대로 이전, 이후 하나를 가져옴

→ 사용자가 이전/이후 값을 가져올 원하는 행 배치를 ORDER BY를 통해 충분히 전달하기

  • DEPTNO를 통해 1차 정렬, 이후 SAL을 통해 2차 정렬하고 이전 값 가져오기
  • DEPTNO를 통해서만 정렬했다면 원하는 값을 얻지 못했을 수 있음

 

FIRST_VALUE, LAST_VALUE
  • 정렬 순서대로 정해진 범위에서의 처음 값, 마지막 값 출력
  • 순서와 범위의 정의에 따라 최솟값과 최댓값 리턴 가능
  • PARTITION BY, ORDER BY 절 생략 가능

 

** 문법

 

 

예1) FIRST_VALUE를 사용한 최소, 최대 출력

  • 어떻게 정렬하는지에 따라 최소, 최대를 모두 출력 가능

 

예2) LAST_VALUE를 사용한 최소, 최대 출력

  • LAST_VALUE로 최대, 최소를 구할 때 정렬 후 연산 범위 설정 없이 DEFAULT로 수행하면 : 처음부터 현재 행까지 중에 최대, 최소를 구하는 것이므로 항상 현재 행이 반환됨
  • 같은 DEPTNO 중 최대값을 LAST_VALUE를 통해 매 행에 출력하고 싶다면 연산 범위를 적절히 조정해야 함
  • OVER(PARTITION BY DEPTNO ORDER BY SAL RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS MAX_VALUE
  • OVER(PARTITION BY DEPTNO ORDER BY SAL DESC RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS MIN_VALUE

 

NTILE
  • 랭을 특정 컬럼 순서에 따라 정해진 수의 그룹으로 나누기 위한 함수
  • 그룹 번호가 리턴됨
  • ORDER BY 필수
  • PARTITION BY를 사용하여 특정 그룹에 대해 또 원하는 수 만큼 그룹 분리 가능
  • 총 행의 수가 명확히 나눠지지 않을 때 앞 그룹의 크기가 더 크게 분리됨
    • 예) 14명 3개 그룹 분리 시 → 5 / 5 / 4

 

** 문법

  • NTILE(N) → N 자리에 몇 개의 그룹으로 나눌 건지 기술

 

예) NTILE을 사용한 그룹 분리

NTILE(2) OVER(ORDER BY SAL)

→ 행이 총 14개라면 순서대로 오름차순 정렬 후 1~7번째 행은 1, 8~14번째 행은 2 반환

 

 

비율 관련 함수

 

1. RATIO_TO_REPORT

  • 각 값의 비율 리턴 (전체 비율 또는 특정 그룹 내 비율 가능)
  • ORDER BY 사용 불가 (순서에 대한 결과가 아님)
  • '값'에 대한 비율

 

** 문법

 

 

2. CUME_DIST

  • 각 행의 수에 대한 누적 비율
  • 특정 값이 전체 데이터 집합에서 차지하는 위치를 백분위 수로 계산하여 출력
  • ORDER BY를 사용하여 누적 비율을 구하는 순서 정함
  • ORDER BY 필수 (위치에 대한 결과)
  • 값이 3개이면 1/3 = 0.33부터 시작 (0부터 시작 X)
  • '순서, 위치'에 대한 비율

 

** 문법

  • PARTITION BY를 통해 그룹 내에서의 위치 비율 출력 가능

 

3. PERCENT_RANK

  • PERCENTILE (분위수) 출력
  • 전체 COUNT 중 상대적 위치 출력 (0~1 범위 내)
  • ORDER BY 필수 (위치에 대한 결과)
  • '순서, 위치'에 대한 비율

 

** 문법

  • PARTITION BY를 통해 그룹 내에서의 위치 비율 출력 가능

 

예1) CUME_DIST와 PERCENT_RANK 비교

  • 첫 번째 행에 대해
    CUME_DIST ≫ 1/N (N은 행의 개수)
    PERCENT_RANK ≫ 0
  • CUME_DIST : 1/N, 2/N, 3/N ... N/N(1)
  • PERCENT_RANK : 0, 1/N-1, 2/N-1, ..., 1

 

예2) 누적 비율 비교

  • RATIO_TO_REPORT(SAL) : DEPTNO가 10인 (1300+2450+5000)에 대한 SAL의 비율 반환
    • 예) 첫 번째 행 DEPTNO = 10, SAL = 1300 → 1300/(1300+2450+5000)의 반올림은 0.15
    • ROUND(값, 2) → 소수점 둘째자리까지 반올림 (셋째자리에서)
  • CUME_DIST() : ORDER BY를 SAL로만 한 경우 최대값인 같은 값에 대해 둘 다 1로 반환
  • ORDER BY를 적절히 조절하여 중복 없이 반환되도록 조절 가능
    • ORDER BY에 두 컬럼 전달 두 값이 모두 같을 때만 RANGE 처리, 그렇지 않으면 각각 연산
  • CUME_DIST는 각 행이 전체 혹은 PARTITION 내에서 차지하고 있는 비율을 의미함
    • 예) MILLER는 10번 부서원 총 3명 중 1명의 비율

 

예3) PERCENT_RANK 예제

  • 사진에 잘렸지만 마지막 행은 TOTAL_PERCENTILE이 1
  • 0부터 1 범위로 표현

 

 

 

 

'sqld' 카테고리의 다른 글

2-14) 계층형 질의  (0) 2024.08.22
2-13) TOP N QUERY  (0) 2024.08.22
2-11) 그룹 함수  (0) 2024.08.21
2-10) 집합 연산자  (0) 2024.08.21
2-9) 서브쿼리  (0) 2024.08.21