March 7, 2009

PostgreSQL Window Functions

Filed under: postgresql — coutinho @ 1:46 am

Como o David Feeter me prometeu na pg-con ano passado o pessoal do postgreSQL implementou as famosas window functions. As “windows” são os dados “sobre” os quais você irá trabalhar. Daí o nome window e daí também o noe da mais famosa delas over.

Um exemplo simples tirado direto da documentação oficial do 8.4 pode nos ajudar a entender o que isso significa na pratica.

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)
O que vemos aí é que foi pedido para calcular a média dos salarios “em cima do departamento”. Algo parecido com um agrupamento pelo departamento, só que sem agrupar na verdade. Com o uso da função partition by o que nós fizemos foi o seguinte, pedimos que o resultado fosse particionado ao invéz de agrupado.

A diferença entre particionar e agrupar é que no particionamento nós mostramos o resultado de nossa função de agregação (avg) para cada uma das linhas que nos fizeram chegar a esse resultado. No caso de um agrupamento nós traríamos apenas a média por desses salários por setor.

Em muitos casos pode ser útil ver não só a media dos salários por setor mas ainda cada linha que nos fez chegar a essa média.

Outro caso o qual me deparei varias vezes em uma migração foi o que a funcao escrita em Pl/SQL precisava apenas mostrar um numero de linha que deveria reinicar a cada mudança de um determinado campo.

Ex:

row_number() | funcionario | setor
——————+—————+————————-
1                      | coutinho     | db
2                      | magno        | db
3                      | marcos       | db
1                      | joao            | desenvolvimento
2                      | chico          | desenvolvimento
3                      | jose            | desenvolvimento
4                      | paulo          | desenvolvimento
(7 rows)

Isso é o resultado de um:

select row_numer() over(partition by setor), funcionario, setor from vw_funcionario_por_setor

Isso que nos dizer que queremos o numero de cada linha dentro da janela delimitada pelo setor.

O resultado visual é uma sequencia numérica que é reiniciada quando muda de setor.

Essas funções me fizeram muita falta, estou ancioso pelo 8.4.

2 Comments »

  1. Todos nós estamos ansiosos coutinho… “:)

    Comment by Guedes — March 7, 2009 @ 6:54 pm

  2. row_number() ?
    Você implementou essa rotina ou é outra novidade da versão nova ?
    Eu conheço ROWNUM no oracle, mas no postgres sempre precisei improvisar com sequencias.

    Comment by Hamilton R. Amorim — June 23, 2009 @ 6:46 pm

RSS feed for comments on this post. TrackBack URI

Leave a comment