윈도우 함수는 테이블에서 로우 집합을 대상으로 계산하는 함수다. 그 로우 집합은 한 로우에 대해서 어떠한 방식으로 관계된 로우들이다. 이 함수는 로우 집합 단위로 계산한다는 점에서 집계 함수와 비슷하다. 집계 함수는 해당 되는 로우 집합에 대해서 하나의 로우로 그 결과물을 보여주지만, 윈도우 함수는 각 로우 단위로 그 처리결과를 출력한다. 숨은 이야기를 하자면, 윈도우 함수는 쿼리 결과의 현재 로우 뿐만 아니라 더 많은 것을 접근할 수 있다.
다음 예제는 각 부서별 평균 임금과 각 직원별 급여를 비교하는 것이다:
SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary;
depname | empno | salary | avg -----------+-------+--------+----------------------- develop | 11 | 5200 | 5020.0000000000000000 develop | 7 | 4200 | 5020.0000000000000000 develop | 9 | 4500 | 5020.0000000000000000 develop | 8 | 6000 | 5020.0000000000000000 develop | 10 | 5200 | 5020.0000000000000000 personnel | 5 | 3500 | 3700.0000000000000000 personnel | 2 | 3900 | 3700.0000000000000000 sales | 3 | 4800 | 4866.6666666666666667 sales | 1 | 5000 | 4866.6666666666666667 sales | 4 | 4800 | 4866.6666666666666667 (10 rows)
첫번째 칼럼부터 세번째 칼럼까지는 empsalary
테이블의
자료 그대로다. 여기서 하나의 로우는 실재 테이블 자료의 실재
로우다. 네번째 칼럼은 depname
칼럼 값을 기준으로
그룹화된 자료의 평균값을 각 로우마다 보여준다. (이 예제에서
보이는 avg
함수는 집계 함수와 그 사용법이
완벽하게 같은데, 뒤에 오는 OVER
절로 판단해서
윈도우 함수로 처리된다.)
윈도우 함수 뒤에는 항상 OVER
절을 사용한다. 이 규칙은
이 함수가 윈도우 함수로 처리할 것인지, 그렇지 않을 것인지를
구분하는 문법상 규칙이다. OVER
절에는
윈도우 함수의 계산 대상이 되는 로우들을 집합화하는 방법을 정의한다.
PARTITION BY
로 정의하는 목록은 같은 그룹인지,
다른 그룹인지 구분하는 기준으로 사용되고, 같은 그룹 내에서는
현재 로우 값도 포함해서 계산 된 윈도우 함수의 결과값을 공유한다.
또한 OVER
절로 집합화 하는 로우들의 정렬 순서를
ORDER BY
절을 사용해서 지정할 수 있다.
(The window ORDER BY
does not even have to match the
order in which the rows are output.) 다음은 그 예제다:
SELECT depname, empno, salary, rank() OVER (PARTITION BY depname ORDER BY salary DESC) FROM empsalary;
depname | empno | salary | rank -----------+-------+--------+------ develop | 8 | 6000 | 1 develop | 10 | 5200 | 2 develop | 11 | 5200 | 2 develop | 9 | 4500 | 4 develop | 7 | 4200 | 5 personnel | 2 | 3900 | 1 personnel | 5 | 3500 | 2 sales | 1 | 5000 | 1 sales | 4 | 4800 | 2 sales | 3 | 4800 | 2 (10 rows)
위에서 보는 바와 같이, 이 결과는 부서명을 기준으로 급여가 많은 자료부터
차례로 출력하는데, 이 때 rank
함수를
사용하여 그 순위를 보여주는 것이다.
rank
함수의 입력 매개 변수는 필요없다. 다음에 오는
OVER
절에서 이 함수에서 처리해야할 모든 입력 정보들이
다 정의되었기 때문이다.
윈도우 함수의 계산 대상이 대는 로우는
FROM
다음부터 WHERE
, GROUP BY
,
HAVING
절로 각 조건에 맞게 걸러진
“가상 테이블”의 각 로우다. 예를 들어,
WHERE
조건절을 통해서 이미 걸러져 버린
로우에 대해서는 원도우 함수의 계산 대상이 되지 않는다. 하나의
쿼리에 여러개의 윈도우 함수를 사용할 수 있다. 이 함수들은
각각의 OVER
절을 사용하여 각각 자료를 집합화 한다. 하지만,
이 집합화 대상이 대는 가상 테이블은 같아야한다.
이미 살펴 보았듯이, ORDER BY
절이 필요 없는 경우라면,
생략할 수 있다. 이와 마찬가지로 PARTITION
BY
절도 생략할 수 있으며, 이것이 생략된다면, 윈도우 함수가 처리하는
같은 집합은 처리 결과 모든 로우의 집합이 된다.
윈도우 함수와 관련된 또 하나 중요한 사항은 다음과 같다:
윈도우 프래임 window frame이라는 개념인데,
구분 대상이 되는 로우 집함들 가운데, 현재 윈도우 함수가
처리 하는 로우 집합을 뜻한다. 많은 윈도우 함수들이
이 윈도우 프래임 단위로 계산을 한다. (물론 전부는 아니다)
초기값으로 ORDER BY
절을 사용하면,
윈도우 프래임은 해당 정렬 방법으로 정렬 해서 순차적으로 현재 로우까지가
된다. ORDER BY
절이 빠지면, 그 구분되는 집합들의
모든 로우가 윈도우 함수의 계산 대상이 된다.
[4]
다음은 sum
윈도우 함수를 사용한 예다:
SELECT salary, sum(salary) OVER () FROM empsalary;
salary | sum --------+------- 5200 | 47100 5000 | 47100 3500 | 47100 4800 | 47100 3900 | 47100 4200 | 47100 4500 | 47100 4800 | 47100 6000 | 47100 5200 | 47100 (10 rows)
위에서 처럼, OVER
절에 ORDER BY
정의를
하지 않았고, PARTITION BY
절을 사용하지 않아서
가상 테이블은 실재 테이블의 전체 자료가 된다. 즉,
모든 로우에는 같은 윈도우 함수의 결과값이 출력된다. 하지만
ORDER BY
정의를 하게 되면 다음과 같이
결과는 전혀 다르게 나온다.
SELECT salary, sum(salary) OVER (ORDER BY salary) FROM empsalary;
salary | sum --------+------- 3500 | 3500 3900 | 7400 4200 | 11600 4500 | 16100 4800 | 25700 4800 | 25700 5000 | 30700 5200 | 41100 5200 | 41100 6000 | 47100 (10 rows)
윈도우 함수는 현재 로우를 포함 해서, 급여가 제일 적은 것부터 차례대로 함수 결과를 그때 그때 출력한다. (여기서 주의할 사항은 윈도우 함수는 현재 로우의 자료를 포함해서 계산 한다는 것이다.)
윈도우 함수는 SELECT
항목 영역 안에서와,
ORDER BY
절에서만 사용할 수 있다. 그외
GROUP BY
절이나, HAVING
,
WHERE
절에서는 사용할 수 없다. 이는
논리적으로 이 함수의 처리 대상이 되는 입력 매개 변수값이
이미 결정이 나야하기 때문이다. 이와 같은 이유로,
윈도우 함수의 입력 매개 변수로 집계 함수의 결과를
사용 할 수는 있지만, 그 반대는 불가능 하다.
윈도우 함수를 사용한 결과에 대한 검색 조건이나, 재 집계가 필요하다면, 서브 쿼리를 사용할 수 있다. 아래 예제 참고:
SELECT depname, empno, salary, enroll_date FROM (SELECT depname, empno, salary, enroll_date, rank() OVER (PARTITION BY depname ORDER BY salary DESC, empno) AS pos FROM empsalary ) AS ss WHERE pos < 3;
윗 쿼리는 rank
값이 3보다 작은 자료들만 출력한다.
여러 개의 윈도우 함수를 함께 쓸 때는 각각 OVER
절을 사용해야하는데, 이 때 지정할 원도우 프래임이 복잡하다면,
그것을 계속 중복 입력해야는 것과, 이로 인해 오류를 낼 가능성 커진다. 이
문제점을 줄이기 위해서 WINDOW
절을 이용한다. 다음은
그 예다:
SELECT sum(salary) OVER w, avg(salary) OVER w FROM empsalary WINDOW w AS (PARTITION BY depname ORDER BY salary DESC);
윈도우 함수에 대한 보다 많은 정보들은 4.2.8절, 9.22절, 7.2.5절, 및 SELECT 설명서 페이지에서 다루고 있다.