Jak mogę dodać kolumnę do bazy danych Postgresql, która nie dopuszcza wartości zerowych?


243

Dodaję nową kolumnę „NOT NULL” do mojej bazy danych Postgresql, używając następującego zapytania (odkażonego dla Internetu):

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

Za każdym razem, gdy uruchamiam to zapytanie, pojawia się następujący komunikat o błędzie:

ERROR:  column "mycolumn" contains null values

Jestem zakłopotany. Gdzie się mylę?

UWAGA: Korzystam głównie z pgAdmin III (1.8.4), ale otrzymałem ten sam błąd, kiedy uruchomiłem SQL z poziomu terminala.

Odpowiedzi:


400

Musisz ustawić wartość domyślną.

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
Niezłe rozwiązanie. Z jakiegoś powodu nie mogłem dostać się do internetowych dokumentów postgres, aby zobaczyć, jaka byłaby do tego składnia.
Sean Bright

4
@SeanBright, możesz uzyskać dostęp do postgres doc offline, wykonując man ALTER_TABLE :)
allan.simon

@ allan.simon Nigdy wcześniej nie korzystałem z PostgreSQL i nigdzie go nie mam.
Sean Bright,

2
Aby wyjaśnić: wartość domyślna jest potrzebna tylko do aktualizacji istniejących wierszy, dlatego można ją natychmiast usunąć. Wszystkie istniejące wiersze zostały zaktualizowane, gdy tabela została zmieniona (co może oczywiście zająć trochę czasu)
MSalters

2
To nie zadziała, jeśli chcesz użyć innej kolumny do obliczenia wartości początkowej dla istniejących wierszy. Odpowiedź j_random_hackera pozwala na to, dzięki czemu jest bardziej niezawodna.
jpmc26

82

Jak zauważyli inni, musisz albo utworzyć kolumnę zerowalną, albo podać wartość DOMYŚLNĄ. Jeśli to nie jest wystarczająco elastyczne (np. Jeśli potrzebujesz w jakiś sposób obliczać nową wartość dla każdego wiersza indywidualnie), możesz skorzystać z faktu, że w PostgreSQL wszystkie polecenia DDL można wykonać w ramach transakcji:

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
nawet w przypadku transakcji NOT NULL jest egzekwowane natychmiast, więc najpierw należy dodać kolumnę, wypełnić wartości, a następnie dodać NOT NULL - jak robi to odpowiedź. (testowany na postgresie 9.6)
Beni Cherniavsky-Paskin

48

Ponieważ wiersze już istnieją w tabeli, ALTERinstrukcja próbuje wstawić NULLdo nowo utworzonej kolumny dla wszystkich istniejących wierszy. Trzeba dodać kolumnę jako dozwoloną NULL, a następnie wypełnić kolumnę żądanymi wartościami, a następnie ustawić ją na NOT NULLpóźniej.


7
Przykład, jak to zrobić, byłby naprawdę miły. W przeciwnym razie rozwiązanie Luca wydaje się bardziej kompletne i gotowe do użycia.
Victor Farazdagi,

5

Musisz zdefiniować wartość domyślną lub zrobić to, co mówi Sean i dodać ją bez ograniczenia zerowego, dopóki nie wypełnisz jej w istniejących wierszach.


2

Określenie wartości domyślnej również działałoby, przy założeniu, że wartość domyślna jest odpowiednia.


2
Poprawiłoby to odpowiedź, dając poprawioną składnię, aby utworzyć kolumnę z wartością domyślną (dla ilustracji).
hardmath

1

Lub utwórz nową tabelę jako temp z dodatkową kolumną, skopiuj dane do tej nowej tabeli, manipulując nią w razie potrzeby, aby wypełnić nową kolumnę, która nie ma wartości zerowej, a następnie zamień tabelę poprzez dwuetapową zmianę nazwy.

Tak, jest to bardziej skomplikowane, ale może być konieczne zrobienie tego w ten sposób, jeśli nie chcesz dużej aktualizacji na stole na żywo.


3
Nie -1 cię, ale myślę, że mogą być z tym subtelne trudności - np. Założę się, że istniejące indeksy, wyzwalacze i widoki będą nadal odnosić się do oryginalnej tabeli, nawet po zmianie nazwy, ponieważ myślę, że przechowują relid tabeli (która się nie zmienia) zamiast jej nazwy.
j_random_hacker

1
Tak, powinienem był powiedzieć, że nowa tabela powinna być dokładną kopią oryginału, łącznie z dodawaniem indeksów i tym podobnych. Mój zły za bycie zbyt krótkim. Powodem tego jest to, że istnieją również subtelne trudności z wykonaniem ZMIANY na stole, który może być na żywo, i czasami trzeba go wystawić.
alphadogg

Na przykład, stosując metodę DOMYŚLNĄ, dodasz tę wartość domyślną do każdego wiersza. Nie jestem pewien, w jaki sposób Postgres blokuje stół. Lub, jeśli kolejność kolumn ma znaczenie, nie można po prostu dodać kolumny za pomocą polecenia ALTER.
alphadogg

W porządku, ALTER TABLE blokuje tabelę zgodnie z dokumentacją PostgreSQL, jednak twoje podejście nietransakcyjne grozi utratą zmian, jeśli tabela rzeczywiście jest aktywna. Sugeruję również, aby każdy kod, który opiera się na kolejności kolumn, był uszkodzony (co oczywiście może być poza twoją kontrolą).
j_random_hacker

2
Takie podejście jest szczególnie problematyczne, jeśli do tabeli odwołują się indeksy kluczy obcych, ponieważ wszystkie one również musiałyby zostać odtworzone.
Aryeh Leib Taurog

0

to zapytanie automatycznie zaktualizuje wartości null

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

-6

To działało dla mnie: :)

ALTER TABLE your_table_name ADD COLUMN new_column_name int;

2
NOT NULLTwoje zapytanie nie ma żadnych ograniczeń. Oczywiście, że działa.
Sylvain,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.