Instale o módulo adicional tablefunc
uma vez por banco de dados, que fornece a função crosstab()
. Desde o Postgres 9.1, você pode usar CREATE EXTENSION
para isso:
CREATE EXTENSION IF NOT EXISTS tablefunc;
Caso de teste aprimorado
CREATE TABLE tbl (
section text
, status text
, ct integer -- "count" is a reserved word in standard SQL
);
INSERT INTO tbl VALUES
('A', 'Active', 1), ('A', 'Inactive', 2)
, ('B', 'Active', 4), ('B', 'Inactive', 5)
, ('C', 'Inactive', 7); -- ('C', 'Active') is missing
Formulário simples - não adequado para atributos ausentes
crosstab(text)
com 1 parâmetro de entrada:
SELECT *
FROM crosstab(
'SELECT section, status, ct
FROM tbl
ORDER BY 1,2' -- needs to be "ORDER BY 1,2" here
) AS ct ("Section" text, "Active" int, "Inactive" int);
Devoluções:
Seção Ativo Inativo
--------- + -------- + ----------
A 1 | 2
B 4 | 5
C 7 | - !!
- Não há necessidade de transmitir e renomear.
- Observe o resultado incorreto para
C
: o valor 7
é preenchido para a primeira coluna. Às vezes, esse comportamento é desejável, mas não para esse caso de uso.
- O formulário simples também é limitado a exatamente três colunas na consulta de entrada fornecida: row_name , categoria , valor . Não há espaço para colunas extras, como na alternativa de 2 parâmetros abaixo.
Formulário seguro
crosstab(text, text)
com 2 parâmetros de entrada:
SELECT *
FROM crosstab(
'SELECT section, status, ct
FROM tbl
ORDER BY 1,2' -- could also just be "ORDER BY 1" here
, $$VALUES ('Active'::text), ('Inactive')$$
) AS ct ("Section" text, "Active" int, "Inactive" int);
Devoluções:
Seção Ativo Inativo
--------- + -------- + ----------
A 1 | 2
B 4 | 5
C | 7 - !!
Observe o resultado correto para C
.
O segundo parâmetro pode ser qualquer consulta que retorne uma linha por atributo que corresponda à ordem da definição da coluna no final. Freqüentemente, você deseja consultar atributos distintos da tabela subjacente como esta:
'SELECT DISTINCT attribute FROM tbl ORDER BY 1'
Isso está no manual.
Como você precisa digitar todas as colunas em uma lista de definições de coluna de qualquer maneira (exceto as variantes predefinidas ), geralmente é mais eficiente fornecer uma lista curta em uma expressão como demonstrada:crosstabN()
VALUES
$$VALUES ('Active'::text), ('Inactive')$$)
Ou (não no manual):
$$SELECT unnest('{Active,Inactive}'::text[])$$ -- short syntax for long lists
Eu usei cotação em dólar para facilitar a cotação.
Você pode até produzir colunas com diferentes tipos de dados com crosstab(text, text)
- desde que a representação de texto da coluna de valor seja uma entrada válida para o tipo de destino. Desta forma, você pode ter os atributos de diferentes tipos e saída text
, date
, numeric
etc. para os respectivos atributos. Há um exemplo de código no final do capítulo crosstab(text, text)
no manual .
db <> mexer aqui
Exemplos avançados
\crosstabview
no psql
O Postgres 9.6 adicionou esse meta-comando ao seu terminal interativo padrão psql . Você pode executar a consulta que usaria como primeiro crosstab()
parâmetro e alimentá-la \crosstabview
(imediatamente ou na próxima etapa). Gostar:
db=> SELECT section, status, ct FROM tbl \crosstabview
Resultado semelhante ao descrito acima, mas é um recurso de representação exclusivamente do lado do cliente . As linhas de entrada são tratadas de maneira ligeiramente diferente, portanto, ORDER BY
não é necessário. Detalhes para \crosstabview
no manual. Existem mais exemplos de código na parte inferior dessa página.
Resposta relacionada no dba.SE de Daniel Vérité (o autor do recurso psql):
A resposta aceita anteriormente está desatualizada.
A variante da função crosstab(text, integer)
está desatualizada. O segundo integer
parâmetro é ignorado. Cito o manual atual :
crosstab(text sql, int N)
...
Versão obsoleta de crosstab(text)
. O parâmetro N
agora é ignorado, pois o número de colunas de valor é sempre determinado pela consulta de chamada
Fundição e renomeação desnecessárias.
Falha se uma linha não tiver todos os atributos. Consulte a variante segura com dois parâmetros de entrada acima para lidar adequadamente com os atributos ausentes.
ORDER BY
é necessário na forma de um parâmetro de crosstab()
. O manual:
Na prática, a consulta SQL sempre deve especificar ORDER BY 1,2
para garantir que as linhas de entrada sejam ordenadas corretamente