web-dev-qa-db-fra.com

Comment ajouter une colonne avec une contrainte de clé étrangère à une table qui existe déjà?

J'ai les tableaux suivants,

CREATE TABLE users (id int PRIMARY KEY);

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

Comment puis-je modifier la table messages de telle sorte que,

  1. une nouvelle colonne appelée sender y est ajoutée
  2. sender est une clé étrangère référençant la table users

Cela n'a pas fonctionné

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

Cette instruction ne crée-t-elle pas également la colonne?

11
Hassan Baig

Ce qui est relativement facile - il vous suffit d'ajouter une autre étape.

La colonne FOREIGN KEY doit exister pour en faire un FK. J'ai fait ce qui suit (depuis ici et documentation ):

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;

Quelques points à noter:

[~ # ~] toujours [~ # ~] donnez à vos clés étrangères des noms significatifs. Être informé que la clé "SYS_C00308108" est violée n'est pas très utile. Voir le violon ici pour le comportement d'Oracle dans ces circonstances, le nom de la clé variera d'un violon à un violon, mais est une chaîne arbitraire commençant par SYS _...)

Compte tenu de votre déclaration:

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

Ce serait un "bon choix" si le SGBDR pouvait créer automatiquement le champ souhaité avec le type de données correspondant au champ référencé. Tout ce que je dirais, c'est que changer DDL est (ou du moins devrait être) une opération rarement utilisée et non quelque chose que vous voudriez faire régulièrement. Cela risque également de s'ajouter à une documentation déjà assez importante.

Au moins PostgreSQL essaie de faire quelque chose de raisonnable - il concatène le nom de la table, le nom du champ FOREIGN KEY Et _fkey Et ajoute même DETAIL: Key (sender_id)=(56) is not present in table "user_". pour donner quelque chose qui pourrait avoir du sens pour un humain être - voir violon ici .

18
Vérace

Je ne sais pas pourquoi tout le monde vous dit que vous devez le faire en deux étapes. En fait, vous ne le faites pas . Vous avez essayé d'ajouter un FOREIGN KEY qui suppose, par conception, que la colonne est là et renvoie cette erreur si la colonne n'est pas là. Si vous ajoutez le COLUMN, vous pouvez explicitement en faire un FOREIGN KEY lors de la création avec REFERENCES,

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

Fonctionnera bien. Vous pouvez voir la syntaxe de ALTER TABLE ici,

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

Avec "action" as,

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

Ces exemples sont même dans les documents,

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;

Mais tout cela n'est pas nécessaire car nous pouvons compter sur le nom automatique et la résolution de la clé primaire (si seul le nom de la table est spécifié, vous faites référence à la clé primaire).

8
Evan Carroll

CASE1: Si vous devez créer une clé étrangère lors de la création d'une nouvelle table

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

Les commandes ci-dessus créeront une table avec le nom 'table1' et trois colonnes nommées 'id' (clé primaire), 'colonne1', 'table2_id' (clé étrangère de table1 qui fait référence à la colonne id de table2).

DATATYPE 'serial' créera la colonne qui utilise ce type de données comme colonne auto-générée, lors de l'insertion de valeurs dans le tableau, vous n'avez pas besoin de mentionner cette colonne du tout, ou vous pouvez donner 'default' sans guillemets à l'endroit de la valeur.

Une colonne de clé primaire est toujours ajoutée à l'index de la table avec la valeur 'tablename_pkey'.

Si une clé étrangère est ajoutée au moment de la création de la table, une CONTRAINTE est ajoutée avec le modèle '(present_table_name) _ (foreign_key_id_name) _fkey'.

Lors de l'ajout d'une clé étrangère, nous devons saisir le mot-clé 'RÉFÉRENCES' à côté du nom de la colonne car nous voulons dire aux postgres que cette colonne fait référence à une table, puis à côté des références, nous devons donner la table pour référence et entre parenthèses donner la nom de colonne de la table référencée, généralement les clés étrangères sont données comme colonnes de clé primaire.

CAS 2: Si vous voulez une clé étrangère vers une table existante sur une colonne existante

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

REMARQUE: les crochets '()' après FOREIGN KEY et REFERENCES tabel2 sont obligatoires, sinon postgres générera une erreur.

0
Ashok Allu

Je connais le problème. Les noms des colonnes sont différents. Peut-être que dans une colonne, il y a un espace ajouté après le nom de votre colonne, alors assurez-vous soigneusement que les noms de vos colonnes ont été nommés exactement de la même manière.

0
XIN WANG