Como posso adicionar uma coluna a um banco de dados Postgresql que não permite nulos?

243

Estou adicionando uma nova coluna "NOT NULL" ao meu banco de dados Postgresql usando a seguinte consulta (higienizada para a Internet):

ALTER TABLE mytable ADD COLUMN mycolumn character varying(50) NOT NULL;

Cada vez que executo essa consulta, recebo a seguinte mensagem de erro:

ERROR:  column "mycolumn" contains null values

Estou perplexo. Onde eu estou errando?

NOTA: Estou usando principalmente o pgAdmin III (1.8.4), mas recebi o mesmo erro ao executar o SQL no Terminal.

Huuuze
fonte

Respostas:

400

Você precisa definir um valor padrão.

ALTER TABLE mytable ADD COLUMN mycolumn character varying(50) NOT NULL DEFAULT 'foo';

... some work (set real values as you want)...

ALTER TABLE mytable ALTER COLUMN mycolumn DROP DEFAULT;
Luc M
fonte
1
Ótima solução. Por algum motivo, não consegui acessar os documentos do postgres on-line para ver qual seria a sintaxe para isso.
Sean Brilhante
4
@SeanBright, você pode acessar a postgres doc desligada fazendo man ALTER_TABLE :)
allan.simon
@ allan.simon Eu nunca usei o PostgreSQL antes e não o tenho instalado em nenhum lugar.
Sean Bright
2
Para esclarecer: o valor padrão é necessário apenas para atualizar as linhas existentes, e é por isso que pode ser descartado imediatamente depois. Todas as linhas existentes foram atualizados quando a tabela foi alterada (que pode demorar algum tempo, obviamente)
MSalters
2
Isso não funcionará se você desejar usar outra coluna para calcular o valor inicial das linhas existentes. A resposta de j_random_hacker permite isso, tornando-o mais robusto.
Jpmc26 5/05
82

Como outros observaram, você deve criar uma coluna anulável ou fornecer um valor PADRÃO. Se isso não for flexível o suficiente (por exemplo, se você precisar que o novo valor seja calculado para cada linha individualmente de alguma forma), você pode usar o fato de que no PostgreSQL todos os comandos DDL podem ser executados dentro de uma transação:

BEGIN;
ALTER TABLE mytable ADD COLUMN mycolumn character varying(50);
UPDATE mytable SET mycolumn = timeofday();    -- Just a silly example
ALTER TABLE mytable ALTER COLUMN mycolumn SET NOT NULL;
COMMIT;
j_random_hacker
fonte
7
mesmo em uma transação, NOT NULL é aplicado imediatamente, portanto, primeiro é necessário adicionar a coluna, preencher os valores e adicionar NOT NULL - como essa resposta. (testado no postgres 9.6)
Beni Cherniavsky-Paskin
48

Como as linhas já existem na tabela, a ALTERinstrução está tentando inserir NULLna coluna recém-criada para todas as linhas existentes. Você precisaria adicionar a coluna como permitir NULL, em seguida, preencha a coluna com os valores desejados e defina-a NOT NULLposteriormente.

Sean Bright
fonte
7
Exemplo de como fazer isso teria sido muito bom. Caso contrário, a solução de Luc parece ser mais completa e pronta para uso.
Victor Farazdagi
5

Você precisa definir um padrão ou fazer o que Sean diz e adicioná-lo sem a restrição nula até preenchê-lo nas linhas existentes.

Paul Tomblin
fonte
2

A especificação de um valor padrão também funcionaria, assumindo que um valor padrão seja apropriado.

Ryan Graham
fonte
2
Melhoraria a resposta para fornecer a sintaxe alterada para criar a coluna com um valor padrão (para ilustração).
hardmath 03/09/2015
1

Ou, crie uma nova tabela como temp com a coluna extra, copie os dados para essa nova tabela enquanto manipula-os conforme necessário para preencher a nova coluna não anulável e, em seguida, troque a tabela por uma alteração de nome em duas etapas.

Sim, é mais complicado, mas você pode precisar fazer dessa maneira se não quiser uma grande atualização em uma mesa ativa.

alphadogg
fonte
3
Eu não fiz -1 com você, mas acho que pode haver dificuldades sutis com isso - por exemplo, estou apostando que os índices, gatilhos e visualizações existentes continuarão se referindo à tabela original mesmo após a renomeação, pois acho que eles armazenam o relid da tabela (que não muda) em vez de seu nome.
j_random_hacker
1
Sim, eu deveria ter declarado que a nova tabela deve ser uma cópia exata do original, incluindo a adição de índices e outros. Minha pena por ser muito breve. A razão para isso é que também há sutis dificuldades em executar um ALTER em uma tabela que pode estar ativa e, às vezes, é necessário montá-lo.
5119 alphadogg
Por exemplo, usando a abordagem PADRÃO, você adicionará esse valor padrão a cada linha. Não tenho certeza de como o Postgres bloqueia uma tabela ao fazer isso. Ou, se a ordem da coluna for importante, você não pode simplesmente adicionar uma coluna com o comando ALTER.
5285 alphadogg
É justo que o ALTER TABLE bloqueie a tabela de acordo com os documentos do PostgreSQL; no entanto, sua abordagem não transacional corre o risco de perder alterações se a tabela estiver realmente ativa. Também sugiro que qualquer código que dependa da ordem das colunas esteja quebrado (que pode estar fora do seu controle, é claro).
j_random_hacker
2
Essa abordagem também é particularmente problemática se a tabela for referenciada por índices de chave estrangeira, pois todos teriam que ser recriados também.
Aryeh Leib Taurog
0

esta consulta atualizará automaticamente os nulos

ALTER TABLE mytable ADD COLUMN mycolumn character varying(50) DEFAULT 'whatever' NOT NULL;
jacktrade
fonte
-6

Isso funcionou para mim: :)

ALTER TABLE your_table_name ADD COLUMN new_column_name int;
timxor
fonte
2
Não há NOT NULLrestrição na sua consulta. Claro que está funcionando.
19417 Sylvain