PostgreSQL: colunas geradas

16

O PostgreSQL suporta colunas geradas ? Também conhecido como colunas virtuais . Eu não estou falando de IDENTITYcolunas .

Não consigo encontrar nenhuma informação sobre esse recurso notável, mas sei que ele está disponível no SQL Server e nas versões mais recentes do MariaDB e MySQL.

O recurso é mencionado no padrão SQL: 2003 e houve alguma discussão nos fóruns do PostgreSQL por volta de 2006, mas não consigo encontrar nada substancial sobre o assunto.

Há alguma discussão sobre SO, mas ela é bastante antiga agora, portanto pode estar desatualizada.

Manngo
fonte
2
Esta resposta relacionada de 2012 no SO pode ser útil : stackoverflow.com/questions/11165450/… Ainda válida.
Erwin Brandstetter
@ErwinBrandstetter Desculpe, perdi este comentário. É um truque útil. Obrigado.
Manngo

Respostas:

17

Não tenho certeza se é isso que você deseja, mas a notação de atributo row.full_namee a função full_name(row)são equivalentes no postgresql.

Isso significa que você toma uma mesa

CREATE TABLE people (
  first_name text,
  last_name text
);

e uma função:

CREATE FUNCTION full_name(people) RETURNS text AS $$
  SELECT $1.first_name || ' ' || $1.last_name;
$$ LANGUAGE SQL;

e chame assim:

select full_name from people

É aquilo que você precisa?

Para acelerar as coisas, você pode criar um índice de expressão:

CREATE INDEX people_full_name_idx ON people
USING GIN (to_tsvector('english', full_name(people)));

Ou armazene tudo em uma exibição materializada.

Exemplo retirado daqui: http://bernardoamc.github.io/sql/2015/05/11/postgres-virtual-columns/

Fabian Zeindl
fonte
2
Essa é a resposta correta. Veja, por exemplo, como o Postgrest se refere a esse comportamento como "colunas computadas".
fiatjaf 8/11
Erro de digitação, eu acho - o select deve ser de select people.full_name from peopleou select full_name(people) from people?
Barguast
Não, funciona assim. O prefixo em "selecione people.full_name from people" pode ser deixado de fora, como no SQL regular.
Fabian Zeindl
Eu perdi essa resposta, vindo por assim dizer, muito depois de desistir. Obrigado pela sugestão.
Manngo
1
Você poderia alterar a resposta aceita então?
Fabian Zeindl
6

Não, atualmente não é suportado (no Postgres 9.6).

A única solução alternativa é usar um gatilho ou uma exibição se for um cálculo simples que você não precisa indexar.

um cavalo sem nome
fonte
Ratos. Suponho que eu poderia ter uma visão materializada se precisar do desempenho. Eu adicionei uma solicitação para o recurso, pois ele já está disponível na competição.
Manngo
1
Não há necessidade de um MVIEW. Uma coluna com um gatilho também permitirá indexar o conteúdo da coluna
a_horse_with_no_name 10/17/17
Eu tenho um problema filosófico com o armazenamento de colunas reais adicionais que são basicamente uma repetição dos outros dados. Des normaliza a mesa.
Manngo 13/03/19
5
Bem, uma coluna computada é exatamente isso: armazenando dados não normalizados. Como o valor da coluna computada é gerado, não importa. Eu não vejo uma diferença conceitual entre uma coluna "real" calculado e um que é gerado através de um gatilho
a_horse_with_no_name
Outra solução alternativa (para alguns casos) é indexar uma expressão.
ypercubeᵀᴹ
5

Sim: GENERATED ALWAYS AS … STORED

O Postgres 12 adiciona a funcionalidade para colunas geradas, conforme mencionado no padrão SQL: 2003 .

O valor é gerado no momento de um INSERTou UPDATE, em seguida, armazenado com a linha como qualquer outro valor.

Um gerado deve ser baseado em uma coluna base da mesma tabela ou em uma função imutável .

A sintaxe é simples, uma cláusula sobre CREATE TABLE:

GENERATED ALWAYS AS ( generation_expr ) STORED 

Exemplo:

CREATE TABLE people (
    ...,
    height_cm NUMERIC,
    height_in NUMERIC GENERATED ALWAYS AS ( height_cm / 2.54 ) STORED
);

Recursos:

  • Pode ser indexado.
  • Parte do padrão SQL.

Ressalvas:

  • Com base nas colunas da mesma tabela (tabelas não relacionadas)
  • Não permitido para particionamento (não pode fazer parte de uma chave de partição)
  • Dados sempre gravados na linha, ocupando espaço no armazenamento
    • O recurso futuro pode oferecer VIRTUAL para valores calculados on-the-fly sem armazenamento
  • Profundidade de geração única (use coluna base, não outra coluna gerada)
  • Não há GERADO POR PADRÃO (você não pode substituir o valor)
  • Não é possível acessar o gen-col no gatilho ANTES (valor ainda não determinado)
  • As funções devem ser imutáveis

Vejo:

Basil Bourque
fonte
Obrigado por essa informação. Vejo que a versão 12 ainda não foi totalmente lançada, mas estou ansiosa por isso. Observo que o PostgreSQL usa a sintaxe mais padrão, mas é o mesmo que o MSSQL. Encontrei as especificações do SQL2003 aqui: sigmodrecord.org/publications/sigmodRecord/0403/… . Eu sempre disse que o SQL é um padrão de movimentação muito lenta e as implementações do DBMS são ainda lentas.
Manngo 17/07/19
0

Dependendo do seu caso de uso, você pode obter esse tipo de comportamento declarando uma nova coluna e preenchendo-a com um gatilho na inserção / atualização.

Eu usaria as respostas acima, se possível, para evitar a duplicação de dados que poderiam ser derivados do que você já tem, mas ele faz o truque e pode ser útil para campos derivados computacionalmente intensos que você deseja calcular uma vez e salvar.

Eu considerei essa abordagem para lidar com um problema em que às vezes tinha apenas 15 dígitos de uma chave de 18 dígitos (os últimos 3 dígitos são apenas uma soma de verificação), mas queria poder impor um relacionamento de chave estrangeira.

Documentos PG sobre gatilhos: https://www.postgresql.org/docs/9.6/sql-createtrigger.html

Exemplo W3: https://www.w3resource.com/PostgreSQL/postgresql-triggers.php

Allen Phelps
fonte