Come posso aggiungere una colonna a un database Postgresql che non consente null?


243

Sto aggiungendo una nuova colonna "NOT NULL" al mio database Postgresql usando la seguente query (disinfettata per Internet):

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

Ogni volta che eseguo questa query, ricevo il seguente messaggio di errore:

ERROR:  column "mycolumn" contains null values

Sono perplesso. Dove sto sbagliando?

NOTA: sto usando principalmente pgAdmin III (1.8.4), ma ho ricevuto lo stesso errore quando ho eseguito l'SQL dal Terminale.

Risposte:


400

Devi impostare un valore predefinito.

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;

1
Bella soluzione. Non ho potuto accedere ai documenti di Postgres online per qualche motivo per vedere quale sarebbe la sintassi per questo.
Sean Bright,

4
@SeanBright, puoi accedere a postgres doc offline facendo man ALTER_TABLE :)
allan.simon,

@ allan.simon Non ho mai usato PostgreSQL prima e non l'ho installato da nessuna parte.
Sean Bright,

2
Per chiarire: il valore predefinito è necessario solo per aggiornare le righe esistenti, motivo per cui può essere eliminato immediatamente dopo. Tutte le righe esistenti sono state aggiornate quando la tabella è stata modificata (il che potrebbe richiedere del tempo, ovviamente)
MSalters,

2
Questo non funzionerà se si desidera utilizzare un'altra colonna per calcolare il valore iniziale per le righe esistenti. La risposta di j_random_hacker lo consente, rendendolo più robusto.
jpmc26,

82

Come altri hanno osservato, è necessario creare una colonna nullable o fornire un valore DEFAULT. Se ciò non è abbastanza flessibile (ad esempio se in qualche modo è necessario calcolare il nuovo valore per ogni riga singolarmente), è possibile utilizzare il fatto che in PostgreSQL, tutti i comandi DDL possono essere eseguiti all'interno di una transazione:

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;

7
anche in una transazione, NOT NULL viene applicato immediatamente, quindi deve prima aggiungere colonna, riempire i valori, quindi aggiungere NOT NULL - come fa questa risposta. (testato su Postgres 9.6)
Beni Cherniavsky-Paskin,

48

Poiché le righe esistono già nella tabella, l' ALTERistruzione sta tentando di inserire NULLnella colonna appena creata per tutte le righe esistenti. Dovresti aggiungere la colonna come consentito NULL, quindi riempire la colonna con i valori desiderati, quindi impostarla in NOT NULLseguito.


7
L'esempio di come farlo sarebbe stato davvero bello. Altrimenti, la soluzione di Luc sembra essere più completa e pronta per l'uso.
Victor Farazdagi,

5

Devi definire un valore predefinito o fare ciò che dice Sean e aggiungerlo senza il vincolo nullo fino a quando non lo hai compilato nelle righe esistenti.


2

Anche la specifica di un valore predefinito funzionerebbe, supponendo che un valore predefinito sia appropriato.


2
Migliorerebbe la risposta per fornire la sintassi modificata per creare la colonna con un valore predefinito (per l'illustrazione).
Hardmath,

1

In alternativa, crea una nuova tabella come temp con la colonna aggiuntiva, copia i dati in questa nuova tabella mentre la manipoli, se necessario, per riempire la nuova colonna non nullable, quindi scambia la tabella tramite una modifica del nome in due passaggi.

Sì, è più complicato, ma potrebbe essere necessario farlo in questo modo se non si desidera un grande AGGIORNAMENTO su un tavolo live.


3
Non ti ho -1, ma penso che potrebbero esserci delle sottili difficoltà in questo - ad esempio, sto scommettendo che gli indici, i trigger e le viste esistenti continueranno a fare riferimento alla tabella originale anche dopo la ridenominazione poiché penso che memorizzino il relid della tabella (che non cambia) piuttosto che il suo nome.
j_random_hacker,

1
Sì, avrei dovuto dichiarare che la nuova tabella dovrebbe essere una copia esatta dell'originale, inclusi l'aggiunta di indici e simili. Il mio male per essere troppo breve. La ragione di ciò è che ci sono anche sottili difficoltà nell'eseguire un ALTER su un tavolo che può essere vivo, e talvolta è necessario metterlo in scena.
alphadogg,

Ad esempio, usando l'approccio DEFAULT, aggiungerai quel valore predefinito ad ogni riga. Non sono sicuro di come Postgres blocchi una tabella mentre lo fa. Oppure, se l'ordine delle colonne è importante, non puoi semplicemente aggiungere una colonna con il comando ALTER.
alphadogg,

Abbastanza giusto, ALTER TABLE blocca la tabella in base ai documenti PostgreSQL, tuttavia il tuo approccio non transazionale rischia di perdere le modifiche se la tabella è effettivamente attiva. Inoltre suggerirei che qualsiasi codice che si basa sull'ordine delle colonne sia rotto (che potrebbe essere al di fuori del tuo controllo ovviamente).
j_random_hacker,

2
Questo approccio è anche particolarmente problematico se la tabella è referenziata da indici di chiavi esterne poiché anche questi dovrebbero essere ricreati.
Aryeh Leib Taurog,

0

questa query aggiornerà automaticamente i valori null

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

-6

Questo ha funzionato per me: :)

ALTER TABLE your_table_name ADD COLUMN new_column_name int;

2
Non ci sono NOT NULLvincoli per la tua query. Certo che funziona.
Sylvain,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.