Wie füge ich einer bereits vorhandenen Tabelle eine Spalte mit einer Fremdschlüsseleinschränkung hinzu?

11

Ich habe die folgenden Tabellen,

CREATE TABLE users (id int PRIMARY KEY);

-- already exists with data
CREATE TABLE message ();

Wie ändere ich die messagesTabelle so, dass,

  1. Eine neue Spalte mit dem Namen senderwird hinzugefügt
  2. Wo senderist ein Fremdschlüssel, der auf die usersTabelle verweist ?

Das hat nicht funktioniert

# ALTER TABLE message ADD FOREIGN KEY (sender) REFERENCES users;
ERROR:  column "sender" referenced in foreign key constraint does not exist

Erstellt diese Anweisung nicht auch die Spalte?

Hassan Baig
quelle
3
Sie müssen die Spalte erstellen, bevor Sie darauf verweisen. Ich würde auch versuchen, die Dokumentation für ALTER TABLE hier zu lesen und die Beispiele sehr genau zu beachten.
Kassandry
Hassan, ich habe diese Frage bereinigt, um DDL zu verwenden, und die Dinge entfernt, die nicht funktionierten. Überprüfen Sie, ob dies die Frage beantwortet: dba.stackexchange.com/a/202564/2639 . Fühlen Sie sich frei, eine dieser Änderungen abzulehnen, ich wollte dies nur für die Nachwelt bereinigen.
Evan Carroll
@ Kassandry dba.stackexchange.com/a/202564/2639
Evan Carroll

Antworten:

18

Was relativ einfach ist - Sie müssen nur einen weiteren Schritt hinzufügen.

Die FOREIGN KEYSpalte muss vorhanden sein, um sie zu einer zu machen FK. Ich habe folgendes gemacht (von hier und der Dokumentation ):

CREATE TABLE x(t INT PRIMARY KEY);

CREATE TABLE y(s INT);

ALTER TABLE y ADD COLUMN z INT;    

ALTER TABLE y
  ADD CONSTRAINT y_x_fkey FOREIGN KEY (z)
      REFERENCES x (t)
      ON UPDATE CASCADE ON DELETE CASCADE;

Ein paar Punkte zu beachten:

IMMER Ihre Fremdschlüssel aussagekräftige Namen geben. Es ist nicht sehr hilfreich zu erfahren, dass der Schlüssel "SYS_C00308108" verletzt wird. In der Geige finden Sie Informationen zum Verhalten von Oracle unter diesen Umständen. Der Schlüsselname variiert von Geige zu Geige, ist jedoch eine beliebige Zeichenfolge, die mit SYS beginnt.

In Anbetracht Ihrer Aussage:

ALTER TABLE message ADD FOREIGN KEY (sender) REFERENCES users;

Es wäre "schön zu haben", wenn das RDBMS automatisch das gewünschte Feld mit dem Datentyp erstellen könnte, der mit dem referenzierten Feld übereinstimmt. Ich würde nur sagen, dass das Ändern von DDL eine selten verwendete Operation ist (oder zumindest sein sollte) und nicht etwas, das Sie regelmäßig durchführen möchten. Es besteht auch die Gefahr, dass eine bereits ziemlich umfangreiche Dokumentation ergänzt wird.

Zumindest versucht PostgreSQL, etwas Vernünftiges zu tun - es verkettet den Tabellennamen, den FOREIGN KEYFeldnamen und _fkeyfügt sogar DETAIL: Key (sender_id)=(56) is not present in table "user_".etwas hinzu, das für einen Menschen sinnvoll sein könnte - siehe Geige hier .

Vérace
quelle
2
Ich nenne meine Fremdschlüssel nie. Sie werden automatisch benannt und sind normalerweise ziemlich nützlich. Der Standardname in diesem Kontext lautet beispielsweise "y_z_fkey". Ich würde behaupten , dass es einen besseren Namen als y_x_fkeywegen Ihrer Verletzung Ihnen nicht sagen , die Spalte Sie sind Einfügen in das verursacht den Fehler. Es ist mir weniger wichtig, wohin es zeigt. Als allgemeine Regel sollten Sie niemals Ihre F - Tasten damit umgehen PostgreSQLs Standardnamen und lassen.
Evan Carroll
Möglicherweise möchten Sie auch die Standardeinstellungen ON UPDATE CASCADE ON DELETE CASCADE;in einem Beispiel nicht überschreiben , insbesondere nicht ohne Grund. Dadurch wird das Beispiel komplexer, und Sie müssen nicht erklären, was es ist. Normalerweise möchte ich nicht, dass Löschungen kaskadieren.
Evan Carroll
1
Ich nenne FKs immer gemäß der Konvention, die das Unternehmen / Projekt beschlossen hat. Es spielt keine Rolle, ob es ist y_x_fkeyoder y_z_fkeyoder x__y_FK, solange es konsistent ist.
Ypercubeᵀᴹ
Ich würde dem sehr zustimmen, wenn Sie einen Vertrag abschließen - wählen Sie eine Konvention aus und halten Sie sich daran und / oder stellen Sie sicher, dass Sie den Konventionen entsprechen, die zuvor mit dem System verwendet wurden / wurden.
Vérace
@EvanCarroll - Wenn die PostgreSQL-Konvention die des Projekts ist oder sich zuvor für Systeme entschieden hat, die möglicherweise nicht PostgreSQL sind, hat ein System möglicherweise beispielsweise mit Oracle oder einem anderen System begonnen, das möglicherweise nicht über die PostgreSQL-Konvention (en) verfügt. Sie könnten argumentieren, dass x_y_z_fk im Fehlerfall die maximal möglichen Informationen liefern könnte! Wählen Sie etwas aus und bleiben Sie dabei, lautet mein Motto, aber lassen Sie sich nicht von einem RDBMS (egal wie gut) Konventionen für Sie festlegen!
Vérace
7

Ich bin mir nicht sicher, warum Ihnen alle sagen, dass Sie dies in zwei Schritten tun müssen. Tatsächlich tust du das nicht . Sie haben versucht, eine hinzuzufügen, FOREIGN KEYdie davon ausgeht, dass die Spalte vorhanden ist, und diesen Fehler auslöst, wenn die Spalte nicht vorhanden ist. Wenn Sie das hinzufügen COLUMN, können Sie es explizit zu einer FOREIGN KEYOn-Erstellung machen mit REFERENCES:

ALTER TABLE message
  ADD COLUMN sender INT
  REFERENCES users;  -- or REFERENCES table(unique_column)

Wird gut funktionieren. Sie können die Syntax von ALTER TABLEhier sehen,

ALTER TABLE [ IF EXISTS ] [ ONLY ] name [ * ]
action [, ... ]

Mit "Aktion" als,

ADD [ COLUMN ] [ IF NOT EXISTS ] column_name data_type [ COLLATE collation ] [ column_constraint [ ... ] ]

Diese Beispiele finden Sie sogar in den Dokumenten.

ALTER TABLE distributors
  ADD CONSTRAINT distfk
  FOREIGN KEY (address)
  REFERENCES addresses (address);

ALTER TABLE distributors
  ADD CONSTRAINT distfk
  FOREIGN KEY (address)
  REFERENCES addresses (address)
  NOT VALID;

All dies wird jedoch nicht benötigt, da wir uns auf die automatische Benennung und die Primärschlüsselauflösung verlassen können (wenn nur der Tabellenname angegeben wird, verweisen Sie auf den Primärschlüssel).

Evan Carroll
quelle
0

FALL1: Wenn Sie beim Erstellen einer neuen Tabelle einen Fremdschlüssel erstellen müssen

CREATE TABLE table1(
id SERIAL PRIMARY KEY,
column1 varchar(n) NOT NULL,
table2_id SMALLINT REFERENCES table2(id)
); 

Mit den obigen Befehlen wird eine Tabelle mit dem Namen 'table1' und drei Spalten mit den Namen 'id' (Primärschlüssel), 'column1', 'table2_id' (Fremdschlüssel von Tabelle1, der auf die ID-Spalte von Tabelle2 verweist) erstellt.

DATATYPE 'serial' erstellt die Spalte, die diesen Datentyp als automatisch generierte Spalte verwendet. Wenn Sie Werte in die Tabelle einfügen, müssen Sie diese Spalte überhaupt nicht erwähnen, oder Sie können 'default' ohne Anführungszeichen an der Wertstelle angeben.

Dem Index der Tabelle wird immer eine Primärschlüsselspalte mit dem Wert 'tablename_pkey' hinzugefügt.

Wenn zum Zeitpunkt der Tabellenerstellung ein Fremdschlüssel hinzugefügt wird, wird ein CONSTRAINT mit dem Muster '(vorhandener_Tabellenname) _ (Fremdschlüssel_ID_Name) _fkey' hinzugefügt.

Wenn wir einen Fremdschlüssel hinzufügen, müssen wir das Schlüsselwort 'REFERENCES' neben dem Spaltennamen eingeben, da wir den Postgres mitteilen möchten, dass diese Spalte auf eine Tabelle verweist, und dann neben den Verweisen die Tabelle als Referenz angeben und in Klammern die Spaltenname der referenzierten Tabelle, normalerweise werden Fremdschlüssel als Primärschlüsselspalten angegeben.

FALL 2: Wenn Sie einen Fremdschlüssel für eine vorhandene Tabelle in einer vorhandenen Spalte wünschen

ALTER TABLE table1
ADD CONSTRAINT table1_table2_id_id_fkey
FOREIGN KEY (table2_id) REFERENCES table2(id);

HINWEIS: Klammern '()' nach FOREIGN KEY und REFERENCES tabel2 sind obligatorisch, da sonst Postgres einen Fehler auslösen.

Ashok Allu
quelle