P.8. Agregações definidas pelo usuário em SQL #

P.8.1. Agregação com concatenação de texto
P.8.2. Agregação com concatenação de inteiros
P.8.3. Agregação com geração de histograma

Essa seção mostra funções de agregação definidas pelo usuário. Os exemplos utilizam os dados da tabela tbl_pessoas mostrada abaixo:

CREATE TABLE tbl_pessoas (
    id          SERIAL,
    nome        TEXT,
    sobrenome   TEXT,
    sexo        CHAR(1),
    altura_cm   INT
);
INSERT INTO tbl_pessoas VALUES (DEFAULT,'Ana','Maria','F',175);
INSERT INTO tbl_pessoas VALUES (DEFAULT,'Manoel','Pacheco','M',168);
INSERT INTO tbl_pessoas VALUES (DEFAULT,NULL,'Barbosa',NULL,NULL);
INSERT INTO tbl_pessoas VALUES (DEFAULT,'Doroteia','Braga',NULL,NULL);
INSERT INTO tbl_pessoas VALUES (DEFAULT,'Manoel','Oliveira','M',181);
INSERT INTO tbl_pessoas VALUES (DEFAULT,'Ana','Fraga','F',165);
INSERT INTO tbl_pessoas VALUES (DEFAULT,'Maria','Pereira','F',164);
INSERT INTO tbl_pessoas VALUES (DEFAULT,'Manoel','Silva','M',153);
\pset null '(nulo)'
\pset border 2
\pset title 'Tabela tbl_pessoas'
SELECT * FROM tbl_pessoas;

                Tabela tbl_pessoas
+----+----------+-----------+--------+-----------+
| id |   nome   | sobrenome |  sexo  | altura_cm |
+----+----------+-----------+--------+-----------+
| 15 | Ana      | Maria     | F      |       175 |
| 16 | Manoel   | Pacheco   | M      |       168 |
| 17 | (nulo)   | Barbosa   | (nulo) |    (nulo) |
| 18 | Doroteia | Braga     | (nulo) |    (nulo) |
| 19 | Manoel   | Oliveira  | M      |       181 |
| 20 | Ana      | Fraga     | F      |       165 |
| 21 | Maria    | Pereira   | F      |       164 |
| 22 | Manoel   | Silva     | M      |       153 |
+----+----------+-----------+--------+-----------+
(8 linhas)

P.8.1. Agregação com concatenação de texto #

Essa função de agregação recebe como parâmetro uma cadeia de caracteres, e retorna como resultado essas cadeias de caracteres concatenadas separadas por ponto-e-vírgula.

CREATE OR REPLACE FUNCTION fun_estado_agrega_texto (text[], text)
RETURNS text[] AS $$
    SELECT array_append($1, $2);
$$ LANGUAGE SQL STRICT;

CREATE OR REPLACE FUNCTION fun_final_agrega_texto (text[])
RETURNS text AS $$
    SELECT array_to_string($1, ';');
$$ LANGUAGE SQL STRICT;

CREATE OR REPLACE AGGREGATE agrega_texto
(
    BASETYPE=text,
    SFUNC = fun_estado_agrega_texto,
    STYPE = text[],
    FINALFUNC = fun_final_agrega_texto,
    INITCOND = '{}'
);

Nesse exemplo, a função agrega_texto é utilizada para colocar em uma linha a lista separada por ponto-e-vírgula de todos os nomes e sobrenomes das pessoas da tabela tbl_pessoas agrupados por sexo.

\pset null '(nulo)'
\pset border 2
\pset title 'Nomes e sobrenomes das pessoas agrupados por sexo'

SELECT sexo, agrega_texto(nome || ' ' || sobrenome) AS pessoas
FROM tbl_pessoas
GROUP BY sexo;

   Nomes e sobrenomes das pessoas agrupados por sexo
+--------+---------------------------------------------+
|  sexo  |                   pessoas                   |
+--------+---------------------------------------------+
| (nulo) | Doroteia Braga                              |
| M      | Manoel Pacheco;Manoel Oliveira;Manoel Silva |
| F      | Ana Maria;Ana Fraga;Maria Pereira           |
+--------+---------------------------------------------+
(3 linhas)

Utilização da função array_accum, definida em Agregações polimórficas e variádicas, para realizar a consulta acima permitindo a comparação dos resultados.

\pset title 'Função array_accum (anycompatible)'

SELECT sexo, array_accum(nome || ' ' || sobrenome) AS pessoas
FROM tbl_pessoas
GROUP BY sexo;

               Função array_accum (anycompatible)
+--------+-----------------------------------------------------+
|  sexo  |                       pessoas                       |
+--------+-----------------------------------------------------+
| (nulo) | {NULL,"Doroteia Braga"}                             |
| M      | {"Manoel Pacheco","Manoel Oliveira","Manoel Silva"} |
| F      | {"Ana Maria","Ana Fraga","Maria Pereira"}           |
+--------+-----------------------------------------------------+
(3 linhas)

P.8.2. Agregação com concatenação de inteiros #

Essa função de agregação recebe como parâmetro um número inteiro, e retorna como resultado uma cadeias de caracteres com esses números concatenados separados por ponto-e-vírgula.

CREATE OR REPLACE FUNCTION fun_estado_agrega_int(int[], int)
RETURNS int[] AS $$
    SELECT array_append($1, $2);
$$ LANGUAGE SQL STRICT;

CREATE OR REPLACE FUNCTION fun_final_agrega_int (int[])
RETURNS text AS $$
    SELECT array_to_string($1, ';');
$$ LANGUAGE SQL STRICT;

CREATE OR REPLACE AGGREGATE agrega_int
(
    BASETYPE = int,
    SFUNC = fun_estado_agrega_int,
    STYPE = int[],
    FINALFUNC = fun_final_agrega_int,
    INITCOND = '{}'
);

Nesse exemplo, a função concat_int é utilizada para colocar em uma linha a lista separada por ponto-e-vírgula de todas as alturas das pessoas da tabela tbl_pessoas agrupadas por sexo.

\pset null '(nulo)'
\pset border 2
\pset title 'Função agrega_int()'

SELECT sexo, agrega_int(altura_cm) AS alturas
FROM tbl_pessoas
GROUP BY sexo;

  Função agrega_int()
+--------+-------------+
|  sexo  |   alturas   |
+--------+-------------+
| (nulo) |             |
| M      | 168;181;153 |
| F      | 175;165;164 |
+--------+-------------+
(3 linhas)

Utilização da função array_accum, definida em Agregações polimórficas e variádicas, para realizar a consulta acima permitindo a comparação dos resultados.

\pset title 'Função array_accum (anycompatible)'

SELECT sexo, array_accum(altura_cm) AS alturas
FROM tbl_pessoas
GROUP BY sexo;

Função array_accum (anycompatible)
+--------+---------------+
|  sexo  |    alturas    |
+--------+---------------+
| (nulo) | {NULL,NULL}   |
| M      | {168,181,153} |
| F      | {175,165,164} |
+--------+---------------+
(3 linhas)

P.8.3. Agregação com geração de histograma #

Essa função de agregação recebe como parâmetro o *, e retorna como resultado um histograma contendo um * para cada ocorrência do valor no grupo. Os valores nulos também são contados.

CREATE OR REPLACE FUNCTION fun_estado_agrega_histograma (text)
RETURNS text AS $$
    SELECT $1 || '*';
$$ LANGUAGE SQL STRICT;

CREATE OR REPLACE AGGREGATE agrega_histograma
(
    BASETYPE = "ANY",
    SFUNC = fun_estado_agrega_histograma,
    STYPE = text,
    INITCOND = ''
);

Nesse exemplo, a função agrega_histograma é chamada para criar um histograma das ocorrências dos nomes das pessoas na tabela tbl_pessoas.

\pset null '(nulo)'
\pset border 2
\pset title 'Histograma dos nomes'

SELECT nome, count(*) AS qtd, agrega_histograma(*) AS histograma
FROM tbl_pessoas
GROUP BY nome
ORDER BY qtd, nome NULLS FIRST;

     Histograma dos nomes
+----------+-----+------------+
|   nome   | qtd | histograma |
+----------+-----+------------+
| (nulo)   |   1 | *          |
| Doroteia |   1 | *          |
| Maria    |   1 | *          |
| Ana      |   2 | **         |
| Manoel   |   3 | ***        |
+----------+-----+------------+
(5 linhas)