Colunas computadas / calculadas / virtuais / derivadas no PostgreSQL


113

O PostgreSQL oferece suporte a colunas computadas / calculadas, como o MS SQL Server? Não consigo encontrar nada na documentação, mas como esse recurso está incluído em muitos outros DBMSs, pensei que poderia estar faltando alguma coisa.

Por exemplo: http://msdn.microsoft.com/en-us/library/ms191250.aspx


Usando a expressão de subconsulta lateral (recurso Postgres), você pode adicionar facilmente mais colunas a cada linha.
— Victor

Respostas:


139

Até Postgres 11 colunas geradas não são suportadas - conforme definido no padrão SQL e implementado por alguns RDBMS incluindo DB2, MySQL e Oracle. Nem as semelhantes "colunas computadas" do SQL Server.

STOREDcolunas geradas são introduzidas com Postgres 12 . Exemplo trivial:

CREATE TABLE tbl (
  int1    int
, int2    int
, product bigint GENERATED ALWAYS AS (int1 * int2) STORED
);

db <> fiddle aqui

VIRTUALcolunas geradas podem vir com uma das próximas iterações. (Não no Postgres 13, ainda).

Relacionado:


Até então , você pode emularVIRTUAL colunas geradas com uma função usando notação de atributo ( tbl.col) que parece e funciona muito como uma coluna gerada virtual . Essa é uma peculiaridade de sintaxe que existe no Postgres por razões históricas e que se encaixa no caso. Esta resposta relacionada tem exemplos de código :

A expressão (parecida com uma coluna) não está incluída em a SELECT * FROM tbl, no entanto. Você sempre tem que listar explicitamente.

Também pode ser compatível com um índice de expressão correspondente - desde que a função seja IMMUTABLE. Gostar:

CREATE FUNCTION col(tbl) ... AS ...  -- your computed expression here
CREATE INDEX ON tbl(col(tbl));

Alternativas

Como alternativa, você pode implementar uma funcionalidade semelhante com um VIEW, opcionalmente acoplado a índices de expressão. Em seguida, SELECT *pode incluir a coluna gerada.

As STOREDcolunas computadas "Persisted" ( ) podem ser implementadas com gatilhos de maneira funcionalmente idêntica.

As visualizações materializadas são um conceito intimamente relacionado, implementado desde o Postgres 9.3 .
Em versões anteriores, pode-se gerenciar MVs manualmente.


Dependendo da quantidade de dados que você está carregando de uma vez, o gatilho pode desacelerar as coisas drasticamente. Em vez disso, pode querer considerar atualizações.
— sam yi

1
Essas soluções são praticamente inúteis (sem grandes mudanças no código para uma base de código sem casos de teste) ao migrar do oracle para o postgres. Existe alguma solução do ponto de vista da migração?
— happybuddha

@happybuddha: Faça sua pergunta como pergunta. Os comentários não são o lugar. Você sempre pode criar um link para esta questão para contexto (e adicionar um comentário aqui para chamar minha atenção e conectar-se à questão relacionada).
— Erwin Brandstetter,

4
A funcionalidade está em desenvolvimento agora: commitfest.postgresql.org/16/1443
— r90t

1
@cryanbhu: Depende dos detalhes de sua configuração e requisitos. Você pode fazer uma nova pergunta com as informações necessárias.
— Erwin Brandstetter,

32

Sim você pode!! A solução deve ser fácil, segura e eficiente ...

Eu sou novo no postgresql, mas parece que você pode criar colunas computadas usando um índice de expressão , emparelhado com uma visão (a visão é opcional, mas torna a vida um pouco mais fácil).

Suponha que meu cálculo seja md5(some_string_field), então eu crio o índice como:

CREATE INDEX some_string_field_md5_index ON some_table(MD5(some_string_field));

Agora, qualquer consulta que atue MD5(some_string_field)usará o índice em vez de computá-lo do zero. Por exemplo:

SELECT MAX(some_field) FROM some_table GROUP BY MD5(some_string_field);

Você pode verificar isso com o explain .

Entretanto, neste ponto, você está contando com os usuários da tabela que sabem exatamente como construir a coluna. Para tornar a vida mais fácil, você pode criar um VIEWem uma versão aumentada da tabela original, adicionando o valor calculado como uma nova coluna:

CREATE VIEW some_table_augmented AS 
   SELECT *, MD5(some_string_field) as some_string_field_md5 from some_table;

Agora, qualquer consulta usando some_table_augmentedpoderá usar some_string_field_md5sem se preocupar com como funciona ... eles apenas obtêm um bom desempenho. O modo de exibição não copia nenhum dado da tabela original, por isso é bom em termos de memória e também de desempenho. Observe, no entanto, que você não pode atualizar / inserir em uma exibição, apenas na tabela de origem, mas se você realmente quiser, acredito que você pode redirecionar inserções e atualizações para a tabela de origem usando regras (posso estar errado nesse último ponto, pois Nunca tentei sozinho).

Editar: parece que se a consulta envolver índices concorrentes, o motor do planejador pode às vezes nem usar o índice de expressão. A escolha parece ser dependente dos dados.


1
Você poderia explicar ou dar um exemplo de if the query involves competing indices?
— dvtan

17

Uma maneira de fazer isso é com um gatilho!

CREATE TABLE computed(
    one SERIAL,
    two INT NOT NULL
);

CREATE OR REPLACE FUNCTION computed_two_trg()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
AS $BODY$
BEGIN
    NEW.two = NEW.one * 2;

    RETURN NEW;
END
$BODY$;

CREATE TRIGGER computed_500
BEFORE INSERT OR UPDATE
ON computed
FOR EACH ROW
EXECUTE PROCEDURE computed_two_trg();

O gatilho é disparado antes que a linha seja atualizada ou inserida. Ele altera o campo que queremos calcular de NEWregistro e, em seguida, retorna esse registro.


Quando o gatilho dispara de forma aguda? Corri acima e fiz isso insert into computed values(1, 2); insert into computed values(4, 8); commit; select * from computed;e acabou de retornar: 1 2 e 4 8
— happybuddha

2
tente insert into computed(one) values(1); insert into computed(one) values(4); commit; select * from computed;o valor da twocoluna será calculado automagicamente!
— Elmer

8

PostgreSQL 12 suporta colunas geradas:

PostgreSQL 12 Beta 1 lançado!

Colunas Geradas

O PostgreSQL 12 permite a criação de colunas geradas que calculam seus valores com uma expressão usando o conteúdo de outras colunas. Este recurso fornece colunas geradas armazenadas, que são calculadas em inserções e atualizações e são salvas no disco. As colunas geradas virtuais, que são calculadas apenas quando uma coluna é lida como parte de uma consulta, ainda não foram implementadas.


Colunas Geradas

Uma coluna gerada é uma coluna especial que sempre é calculada a partir de outras colunas. Portanto, é para colunas o que uma visão é para tabelas.

CREATE TABLE people (
    ...,
    height_cm numeric,
    height_in numeric GENERATED ALWAYS AS (height_cm * 2.54) STORED
);

db <> demonstração de violino



1

Bem, não tenho certeza se é isso que você quer dizer, mas Posgres normalmente suporta sintaxe ETL "fictícia". Eu criei uma coluna vazia na tabela e então precisei preenchê-la com registros calculados dependendo dos valores na linha.

UPDATE table01
SET column03 = column01*column02; /*e.g. for multiplication of 2 values*/
  1. É tão fictício que suspeito que não seja o que Você está procurando.
  2. Obviamente, não é dinâmico, você o executa uma vez. Mas nenhum obstáculo para acioná-lo.

0

Eu tenho um código que funciona e uso o termo calculado, não estou no postgresSQL puro embora rodemos no PADB

aqui está como é usado

create table some_table as
    select  category, 
            txn_type,
            indiv_id, 
            accum_trip_flag,
            max(first_true_origin) as true_origin,
            max(first_true_dest ) as true_destination,
            max(id) as id,
            count(id) as tkts_cnt,
            (case when calculated tkts_cnt=1 then 1 else 0 end) as one_way
    from some_rando_table
    group by 1,2,3,4    ;

O que é exatamente PADB?
— Gherman

O banco de dados analítico do ParAccel é antigo, mas bom ... en.wikipedia.org/wiki/ParAccel
— Wired604

Mas como isso se relaciona com uma pergunta sobre Postgres? Claro que há muitos bancos de dados com suporte para colunas computadas.
— Gherman

ah desculpe, eu não perdi tempo para voltar ao contexto ... PADB é baseado em postgress!
— Wired604

-6

Uma solução leve com restrição de verificação:

CREATE TABLE example (
    discriminator INTEGER DEFAULT 0 NOT NULL CHECK (discriminator = 0)
);

6
Como isso está relacionado ao conceito de coluna calculada? Você se importaria de explicar?
— Erwin Brandstetter

4
Concordo, não está diretamente relacionado. Mas é uma substituição para um caso simples quando você só precisa fazer algo parecido field as 1 persisted.
— cinereo

2
Uma descrição realmente teria sido boa. Acho que esta resposta é que se o cálculo pode ser feito com a cláusula padrão, você pode usar um padrão e uma restrição de verificação para evitar que alguém altere o valor.
— Ross Bradbury

@Ross Bradbury: Concordo, mas isso só funciona para inserção. Não funcionaria se uma coluna dependente fosse atualizada.
— Stefan Steiger
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.