Wie füge ich einer vorhandenen Tabelle in PostgreSQL einen automatisch inkrementierenden Primärschlüssel hinzu?

190

Ich habe eine Tabelle mit vorhandenen Daten. Gibt es eine Möglichkeit, einen Primärschlüssel hinzuzufügen, ohne die Tabelle zu löschen und neu zu erstellen?

xRobot
quelle

Antworten:

354

( Aktualisiert - Danke an die Leute, die kommentiert haben )

Moderne Versionen von PostgreSQL

Angenommen, Sie haben eine Tabelle mit dem Namen test1, zu der Sie eine automatisch inkrementierende Primärschlüsselspalte id(Ersatzspalte) hinzufügen möchten . Der folgende Befehl sollte in neueren Versionen von PostgreSQL ausreichen:

   ALTER TABLE test1 ADD COLUMN id SERIAL PRIMARY KEY;

Ältere Versionen von PostgreSQL

In alten Versionen von PostgreSQL (vor 8.x?) Mussten Sie die ganze Drecksarbeit erledigen. Die folgende Befehlsfolge sollte den Trick ausführen:

  ALTER TABLE test1 ADD COLUMN id INTEGER;
  CREATE SEQUENCE test_id_seq OWNED BY test1.id;
  ALTER TABLE test ALTER COLUMN id SET DEFAULT nextval('test_id_seq');
  UPDATE test1 SET id = nextval('test_id_seq');

Auch in neueren Versionen von Postgres entspricht dies in etwa dem obigen Einzelbefehl.

leonbloy
quelle
3
Ich verwende ORACLE, daher kann das Teilen für ORACLE-Leute nützlich sein. In ORACLE: ALTER TABLE TEST1 ADD ID NUMBER; UPDATE TEST1 SET ID = TEST1_SEQ.NEXTVAL; ALTER TABLE TEST1 ADD PRIMARY KEY (ID); Erstellen Sie eine Sequenz TEST1_SEQ, bevor Sie die UPDATE-Anweisung ausführen
msbyuva
Beachten Sie, dass ADD PRIMARY KEYauch ein erstellt wirdNOT NULL erwartungsgemäß und gewünscht Einschränkung (getestet in Postgres 9.3) erstellt wird.
Jared Beck
19
In Postgres können Sie überhaupt einen einzigen Befehl verwendenALTER TABLE test1 ADD COLUMN id SERIAL PRIMARY KEY;
resnyanskiy
1
Nach dem Kommentar von @ resnyanskiy funktioniert dies auch dann, wenn Daten in der Tabelle enthalten sind. IDs werden ausgefüllt und es wird keine Null-Einschränkung festgelegt. Die gesamte Antwort kann durch die Zeile in diesem Kommentar ersetzt werden.
Synesso
1
@EricWang Danke, Eric, du hast Recht - ich glaube, dass dies vor einigen Jahren (Jahren) nicht funktioniert hat, aber ich bin mir nicht sicher. Verwandelte die Antwort in ein Community-Wiki.
Leonbloy
57
ALTER TABLE test1 ADD COLUMN id SERIAL PRIMARY KEY;

Das ist alles was Sie brauchen:

  1. Fügen Sie die idSpalte hinzu
  2. Füllen Sie es mit einer Sequenz von 1 bis count (*).
  3. Setzen Sie es als Primärschlüssel / nicht null.

@Resnyanskiy, der diese Antwort in einem Kommentar gegeben hat, wird gutgeschrieben.

Synesso
quelle
2
Dies sollte als Antwort markiert werden und die Antwort sollte @resnyanskiy
Eric Wang
Ich musste zuerst den Schlüssel fallen lassen und dann diesen ausführen. ALTER TABLE <table> DROP CONSTRAINT <pkey_name>;
Josh Robertson
10

So verwenden Sie eine Identitätsspalte in Version 10:

ALTER TABLE test 
ADD COLUMN id { int | bigint | smallint}
GENERATED { BY DEFAULT | ALWAYS } AS IDENTITY PRIMARY KEY;

Eine Erläuterung der Identitätsspalten finden Sie unter https://blog.2ndquadrant.com/postgresql-10-identity-columns/ .

Für den Unterschied zwischen GENERATED BY DEFAULT und GENERATED IMMER siehe https://www.cybertec-postgresql.com/de/sequences-gains-and-pitfalls/ .

Informationen zum Ändern der Reihenfolge finden Sie unter https://popsql.io/learn-sql/postgresql/how-to-alter-sequence-in-postgresql/ .

jhoanna
quelle
Das Problem mit dieser Lösung ist, dass, wenn die Tabelle bereits Zeilen enthält, Sie eine Fehlermeldung erhalten:SQL Error [23502]: ERROR: column "id" contains null values
Isapir
3
@isapir: In früheren Versionen (S. 10 und 10.1) ist ein Fehler aufgetreten, der diesen Fehler verursacht hat. Es wurde mit S. 10.2 behoben. Details hier: dba.stackexchange.com/q/200143/3684
Erwin Brandstetter
Danke @ erwin-brandstetter
Isapir
Ein Jahr später fand ich diese Antwort wieder, Fehler anscheinend behoben, positiv bewertet;)
Isapir
2

Ich bin hier gelandet, weil ich auch so etwas gesucht habe. In meinem Fall habe ich die Daten aus einer Reihe von Staging-Tabellen mit vielen Spalten in eine Tabelle kopiert und gleichzeitig der Zieltabelle Zeilen-IDs zugewiesen. Hier ist eine Variante der oben genannten Ansätze, die ich verwendet habe. Ich habe die serielle Spalte am Ende meiner Zieltabelle hinzugefügt. Auf diese Weise muss ich in der Insert-Anweisung keinen Platzhalter dafür haben. Dann füllte eine einfache Auswahl * in der Zieltabelle diese Spalte automatisch aus. Hier sind die beiden SQL-Anweisungen, die ich in PostgreSQL 9.6.4 verwendet habe.

ALTER TABLE target ADD COLUMN some_column SERIAL;
INSERT INTO target SELECT * from source;
Dean Sha
quelle