Aqui está uma versão curta e agradável usando a instrução "DO":
DO $$
BEGIN
BEGIN
ALTER TABLE <table_name> ADD COLUMN <column_name> <column_type>;
EXCEPTION
WHEN duplicate_column THEN RAISE NOTICE 'column <column_name> already exists in <table_name>.';
END;
END;
$$
Você não pode passar isso como parâmetros, precisará fazer a substituição de variáveis na string no lado do cliente, mas essa é uma consulta independente que somente emite uma mensagem se a coluna já existir, adiciona se não existir e continuará a falhar em outros erros (como um tipo de dados inválido).
Eu não recomendo executar QUALQUER desses métodos se forem seqüências aleatórias provenientes de fontes externas. Não importa qual método você use (cadeias dinâmicas cleint ou do lado do servidor executadas como consultas), seria uma receita para o desastre, pois abre para ataques de injeção de SQL.
DO $$ BEGIN BEGIN CREATE INDEX type_idx ON table1 USING btree (type); EXCEPTION WHEN duplicate_table THEN RAISE NOTICE 'Index exists.'; END; END;$$;
a mesma abordagem emCREATE INDEX
;) Obrigado pela sua resposta,DO $$
falha. Eu tentei oDO $$;
que também falhou, até começar o bloco com oDO $$DECLARE r record;
qual é dado um exemplo nos documentos do dev postgres .END; $$
é um erro de sintaxe (Postgres 9.3), eu tive que usar emEND $$;
vez dissoEXCEPTION
) é um pouco mais geral e pode ser empregada para tarefas que não possuemIF NOT EXISTS
sintaxe - por exemploALTER TABLE ... ADD CONSTRAINT
.Com o Postgres 9.6, isso pode ser feito usando a opção
if not exists
fonte
ADD CONSTRAINT IF NOT EXISTS
ainda não há .Ligar:
Retorna
TRUE
com sucesso, caso contrárioFALSE
(a coluna já existe).Gera uma exceção para nome de tabela ou tipo inválido.
Por que outra versão?
Isso pode ser feito com uma
DO
instrução, mas asDO
instruções não podem retornar nada. E se for para uso repetido, eu criaria uma função.Eu uso os tipos de identificador de objeto
regclass
eregtype
para_tbl
e_type
que a) impede a injeção de SQL eb) verifica a validade de ambos imediatamente (da maneira mais barata possível). O nome da coluna_col
ainda precisa ser limpoEXECUTE
comquote_ident()
. Mais explicações nesta resposta relacionada:format()
requer o Postgres 9.1+. Para versões mais antigas concatenar manualmente:Você pode qualificar o nome da tabela com esquema, mas não precisa.
Você pode citar duas vezes os identificadores na chamada de função para preservar palavras reservadas e em maiúsculas e minúsculas (mas não deve usar nada disso).
Eu pergunto em
pg_catalog
vez doinformation_schema
. Explicação detalhada:Blocos contendo uma
EXCEPTION
cláusula como a resposta atualmente aceita são substancialmente mais lentos. Isso geralmente é mais simples e rápido. A documentação:fonte
DO
declaração, uma pequena modificação para aceitarDEFAULT
e isso funcionou perfeitamente!A consulta de seleção a seguir retornará
true/false
, usando aEXISTS()
funçãoe use a seguinte instrução SQL dinâmica para alterar sua tabela
fonte
Para quem usa o Postgre 9.5+ (acredito que a maioria de vocês usa), existe uma solução bastante simples e limpa
fonte
a função abaixo verificará a coluna, se existir, retorne a mensagem apropriada; caso contrário, a coluna será adicionada à tabela.
fonte
Esta é basicamente a solução da sola, mas apenas limpou um pouco. É diferente o suficiente para eu não apenas querer "melhorar" sua solução (mais, acho que isso é rude).
A principal diferença é que ele usa o formato EXECUTE. O que eu acho que é um pouco mais limpo, mas acredito que significa que você deve estar no PostgresSQL 9.1 ou mais recente.
Isso foi testado na 9.1 e funciona. Nota: Irá gerar um erro se o esquema / nome_tabela / ou tipo_de_dados for inválido. Isso pode "consertar", mas pode ser o comportamento correto em muitos casos.
uso:
fonte
Podem ser adicionados aos scripts de migração que invocam a função e descartam quando concluídos.
fonte
No meu caso, pela forma como foi criado, é um pouco difícil para nossos scripts de migração atravessar esquemas diferentes.
Para contornar isso, usamos uma exceção que capturou e ignorou o erro. Isso também teve o bom efeito colateral de ser muito mais fácil de olhar.
No entanto, tenha cuidado para que as outras soluções tenham suas próprias vantagens que provavelmente superam essa solução:
fonte
Você pode fazer isso da seguinte maneira.
Portanto, ele eliminará a coluna se ela já existir. E, em seguida, adicione a coluna à tabela específica.
fonte
Basta verificar se a consulta retornou um nome da coluna.
Caso contrário, execute algo como isto:
Onde você coloca algo útil para 'x' e 'y' e, claro, um tipo de dados adequado onde eu usei int.
fonte