Wie kann ich einer Postgresql-Datenbank eine Spalte hinzufügen, die keine Nullen zulässt?

243

Ich füge meiner Postgresql-Datenbank eine neue Spalte "NOT NULL" hinzu, indem ich die folgende Abfrage verwende (für das Internet bereinigt):

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

Jedes Mal, wenn ich diese Abfrage ausführe, erhalte ich die folgende Fehlermeldung:

ERROR:  column "mycolumn" contains null values

Ich bin ratlos. Wo gehe ich falsch?

HINWEIS: Ich verwende hauptsächlich pgAdmin III (1.8.4), habe jedoch den gleichen Fehler erhalten, als ich SQL über Terminal ausgeführt habe.

Huuuze
quelle

Antworten:

400

Sie müssen einen Standardwert festlegen.

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.
quelle
1
Schöne Lösung. Ich konnte aus irgendeinem Grund nicht zu den Online-Postgres-Dokumenten gelangen, um zu sehen, wie die Syntax dafür aussehen würde.
Sean Bright
4
@ SeanBright, können Sie offline auf postgres doc zugreifen, indem Sie man ALTER_TABLE :)
allan.simon
@ allan.simon Ich habe PostgreSQL noch nie benutzt und ich habe es nirgendwo installiert.
Sean Bright
2
Zur Verdeutlichung: Der Standardwert wird nur zum Aktualisieren vorhandener Zeilen benötigt, weshalb er unmittelbar danach gelöscht werden kann. Alle vorhandenen Zeilen wurden aktualisiert, als die Tabelle geändert wurde (was natürlich einige Zeit dauern kann)
MSalters
2
Dies funktioniert nicht, wenn Sie eine andere Spalte verwenden möchten, um den Anfangswert für vorhandene Zeilen zu berechnen. Die Antwort von j_random_hacker ermöglicht dies und macht es robuster.
jpmc26
82

Wie andere beobachtet haben, müssen Sie entweder eine nullfähige Spalte erstellen oder einen DEFAULT-Wert angeben. Wenn dies nicht flexibel genug ist (z. B. wenn der neue Wert für jede Zeile einzeln berechnet werden muss), können Sie die Tatsache verwenden, dass in PostgreSQL alle DDL-Befehle innerhalb einer Transaktion ausgeführt werden können:

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
quelle
7
Selbst in einer Transaktion wird NOT NULL sofort erzwungen. Sie müssen also zuerst eine Spalte hinzufügen, Werte füllen und dann NOT NULL hinzufügen - wie dies bei dieser Antwort der Fall ist. (getestet auf Postgres 9.6)
Beni Cherniavsky-Paskin
48

Da die Tabelle bereits Zeilen enthält, ALTERversucht die Anweisung, NULLfür alle vorhandenen Zeilen in die neu erstellte Spalte einzufügen . Sie müssten die Spalte als zulässig hinzufügen NULL, dann die Spalte mit den gewünschten Werten füllen und anschließend festlegen NOT NULL.

Sean Bright
quelle
7
Ein Beispiel dafür wäre wirklich schön gewesen. Ansonsten scheint Lucs Lösung vollständiger und gebrauchsfertiger zu sein.
Victor Farazdagi
5

Sie müssen entweder einen Standard definieren oder das tun, was Sean sagt, und ihn ohne die Null-Einschränkung hinzufügen, bis Sie ihn in die vorhandenen Zeilen eingetragen haben.

Paul Tomblin
quelle
2

Die Angabe eines Standardwerts würde auch funktionieren, vorausgesetzt, ein Standardwert ist angemessen.

Ryan Graham
quelle
2
Es würde die Antwort verbessern, die geänderte Syntax zum Erstellen der Spalte mit einem Standardwert anzugeben (zur Veranschaulichung).
Hardmath
1

Oder erstellen Sie eine neue Tabelle als temporär mit der zusätzlichen Spalte, kopieren Sie die Daten in diese neue Tabelle, während Sie sie nach Bedarf bearbeiten, um die nicht nullbare neue Spalte zu füllen, und tauschen Sie die Tabelle dann über eine zweistufige Namensänderung aus.

Ja, es ist komplizierter, aber Sie müssen es möglicherweise so machen, wenn Sie kein großes UPDATE auf einem Live-Tisch möchten.

alphadogg
quelle
3
Ich habe Sie nicht -1, aber ich denke, es kann subtile Schwierigkeiten geben - z. B. wette ich, dass vorhandene Indizes, Trigger und Ansichten auch nach der Umbenennung weiterhin auf die ursprüngliche Tabelle verweisen, da ich denke, dass sie die speichern Relid der Tabelle (die sich nicht ändert) statt ihres Namens.
j_random_hacker
1
Ja, ich hätte sagen sollen, dass die neue Tabelle eine exakte Kopie des Originals sein sollte, einschließlich des Hinzufügens von Indizes und dergleichen. Mein schlechtes, weil ich zu kurz bin. Der Grund dafür ist, dass es auch subtile Schwierigkeiten gibt, einen ALTER an einem Tisch auszuführen, der möglicherweise live ist, und manchmal müssen Sie ihn inszenieren.
Alphadogg
Mit dem DEFAULT-Ansatz fügen Sie beispielsweise jeder Zeile diesen Standardwert hinzu. Ich bin mir nicht sicher, wie Postgres dabei einen Tisch abschließt. Wenn die Spaltenreihenfolge wichtig ist, können Sie mit dem Befehl ALTER nicht einfach eine Spalte hinzufügen.
Alphadogg
Fairerweise sperrt ALTER TABLE die Tabelle gemäß den PostgreSQL-Dokumenten. Ihr nicht-transaktionaler Ansatz kann jedoch Änderungen verlieren, wenn die Tabelle tatsächlich aktiv ist. Außerdem würde ich vorschlagen, dass jeder Code, der sich auf die Spaltenreihenfolge stützt, fehlerhaft ist (was natürlich außerhalb Ihrer Kontrolle liegt).
j_random_hacker
2
Dieser Ansatz ist auch besonders problematisch, wenn die Tabelle von Fremdschlüsselindizes referenziert wird, da diese ebenfalls alle neu erstellt werden müssten.
Aryeh Leib Taurog
0

Diese Abfrage aktualisiert die Nullen automatisch

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

Das hat bei mir funktioniert: :)

ALTER TABLE your_table_name ADD COLUMN new_column_name int;
timxor
quelle
2
Es gibt keine NOT NULLEinschränkung für Ihre Abfrage. Natürlich funktioniert es.
Sylvain