Window function
PostgreSQL 에서 Window function 을 제공한다. ref. 2 을 보면 이런 Window Function 을 제공하는 DB 를 볼 수 있다. 많이들 사용하는 MySQL 에서는 제공하지 않는다. 하지만 Oracle 에서는 제공한다. 여하튼 이녀석의 사용법을 대략적으로 알아보자.
window function 에 대한 이야기는 ref. 1 에 나와있다. 간략하게 이야기 하면, aggregate function 처럼 어떤 계산을 해준다. 하지만 aggregate function 의 결과가 하나의 row 로 보여진다면, 이 window function 은 row 마다 결과를 보여준다.
결과적으로 동작이 조금 달라서 이름을 다르게 지었다고 보면 된다. 실제로 PostgreSQL 에서 Aggregate function 을 만들고, 그녀석을 window function 처럼 사용할 수 있다.
예제
avg()
여하튼 ref. 1 에 있는 예제를 한 번 보자.SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary;
위의 sql 을 해석하면 아래와 같다.
- empsalary table 에서 salary 에 대한 avg() 를 구한다. 그런데 avg() 는 "depname 칼럼의 값"을 구분(partition)해서 구한다.
- 주의할 점은 OVER 가 들어가야 window function 으로 인식한다. 그렇지 않으면 그냥 aggregation 이 된다.
만약 group by 를 사용한다면, 아래처럼 바꿀 수 있을 것이다.
SELECT depname, avg(salary) OVER (PARTITION BY depname) FROM empsalary GROUP BY depname;
결과는 아래와 같다.
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)
rank()
SELECT depname, empno, salary, rank() OVER (PARTITION BY depname ORDER BY salary DESC) FROM empsalary;
ORDER BY
이 window function 에서 OVER 부분에 들어가는 ORDER BY 는 역할이 좀 다르다. 이 partition 안에서 row 들의 집합을 window frame 이라고 하는데, 많은 window function 이 partition 전체에서 동작하지 않고 이 window frame 의 row 들에서 동작한다.ORDER BY 가 없으면 기본적으로 frame (window frame)은 partition 의 모든 row 가 된다. 그런데 ORDER BY 가 OVER 에 들어가면 ORDER BY 한 column 의 각각의 row 가 window frame 이 된다. 이 때 중복된 값은 같은 frame 이 된다.
ref. 1 의 예제를 보면, 이해가 쉽다.
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)
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)
2개의 column 값 더해서 새로운 값
이번에는 2개의 rank 를 구하고, 이것을 더해보자.SELECT t.code, rank+rank_2 AS sum_rank from ( SELECT code, market, rank() OVER (PARTITION BY market ORDER BY price DESC) AS rank, rank() OVER (ORDER BY price DESC) AS rank_2 FROM test_market ) AS t ORDER BY sum_rank DESC;test_market 이라는 table 에서 2개의 rank 를 구하는데, 1개는 market 값별로 price 로 DESC 정렬해서 rank 를 구하고, 다른 한개(rank_2)는 그냥 price 별로 DESC 정렬해서 구한다.
이렇게 나온 순위(rank) 를 더해서 sum_rank 를 구한다.
그리고 이것을 DESC 정렬한다.
함수 종류
이런 식으로 사용할 수 있는 함수가 몇개 있다. 나열해 보면 아래와 같다.[참고 : PostgreSQL: Documentation: 9.2: Window Functions]- row_number
- rank
- dense_rank
- percent_rank
- cume_dist
- ntile
- lag
- lead
- first_value
- last_value
- nth_value
이런 window function 은 aggregate function 을 만들면 된다. 아래를 참고하자.
Reference
- PostgreSQL: Documentation: 9.5: Window Functions
- The Difference Between ROW_NUMBER(), RANK(), and DENSE_RANK() | Java, SQL and jOOQ.
댓글 없음:
댓글 쓰기