PostgreSQL - l'insertion / la mise à jour viole les contraintes de clé étrangère

12

Je suis un nouveau dans postgreSQL. J'ai 3 tables, une table fait référence aux clés primaires des 2 autres tables. Mais je n'ai pas pu insérer de données dans le Table3. Voir le code ci-dessous:

DROP TABLE Table1 CASCADE;
CREATE TABLE Table1(
  "DataID" bigint NOT NULL DEFAULT '0',
  "AdData" integer DEFAULT NULL,
  PRIMARY KEY ("DataID")
);

DROP TABLE IF EXISTS Table2 CASCADE;
CREATE TABLE Table2 (
  "Address" numeric(20) NOT NULL DEFAULT '0',
  "Value" numeric(20) DEFAULT NULL,
  PRIMARY KEY ("Address")
);

DROP TABLE IF EXISTS Table3 CASCADE; 
CREATE TABLE table3 (   
  "ID" bigint NOT NULL DEFAULT '0',   
  "DataID" bigint DEFAULT NULL,   
  "Address" numeric(20) DEFAULT NULL,   
  "Data" bigint DEFAULT NULL,
   PRIMARY KEY ("ID"),   
   FOREIGN KEY ("DataID") REFERENCES Table1("DataID") on delete cascade on update cascade,   
   FOREIGN KEY ("Address") REFERENCES Table2("Address") on delete cascade on update cascade
);

ERREUR: l'insertion ou la mise à jour sur la table "Table3" viole la contrainte de clé étrangère "Table3_DataID_fkey" DÉTAIL: La clé (DataID) = (27856) n'est pas présente dans la table "Table1".

Lorsque j'ai essayé d'insérer des données dans les 3 tables, une erreur s'est produite. J'ai référé la documentation postgreSQL et changé mon code comme suit: (Malheureusement, il a montré une autre erreur)

DROP TABLE Table1 CASCADE;
CREATE TABLE Table1(
  "DataID" bigint NOT NULL DEFAULT '0',
  "AdData" integer DEFAULT NULL,
  PRIMARY KEY ("DataID")
);

DROP TABLE IF EXISTS Table2 CASCADE;
CREATE TABLE Table2 (
  "Address" numeric(20) NOT NULL DEFAULT '0',
  "Value" numeric(20) DEFAULT NULL,
  PRIMARY KEY ("Address")
);

DROP TABLE IF EXISTS Table3 CASCADE; 
CREATE TABLE table3 (   
  "ID" bigint NOT NULL DEFAULT '0',   
  "DataID" bigint DEFAULT NULL REFERENCES Table1 ON DELETE RESTRICT,
  "Address" numeric(20) DEFAULT NULL REFERENCES Table2 ON DELETE CASCADE, 
  "Data" bigint DEFAULT NULL,
   PRIMARY KEY ("ID"),   
   PRIMARY KEY("DataID", "Address")
);

ERREUR: plusieurs clés primaires pour la table "Table3" ne sont pas autorisées LIGNE 65: CLÉ PRIMAIRE ("DataID", "Adresse")

S'il vous plaît, aidez-moi ... Comment puis-je créer la référence?

J'ai changé le IDas UNIQUEet supprimé la ligne PRIMARY KEY ("ID"). À ce moment, il montre une autre erreur comme:

ERREUR: la valeur de clé en double viole la contrainte unique "Table3_pkey"

Haseena
la source

Réponses:

17

Il y a quelques problèmes avec vos tables. Je vais essayer d'aborder les clés étrangères, car vous avez posé des questions à leur sujet :)

Mais avant cela, nous devons nous rendre compte que les deux ensembles de tables (les trois premiers que vous avez créés et le deuxième ensemble, que vous avez créé après avoir supprimé le premier ensemble) sont les mêmes. Bien sûr, la définition de Table3dans votre deuxième tentative a des erreurs de syntaxe et de logique, mais l'idée de base est:

CREATE TABLE table3 (   
  "ID" bigint NOT NULL DEFAULT '0',   
  "DataID" bigint DEFAULT NULL,   
  "Address" numeric(20) DEFAULT NULL,   
  "Data" bigint DEFAULT NULL,
   PRIMARY KEY ("ID"),   
   FOREIGN KEY ("DataID") REFERENCES Table1("DataID") on delete cascade on update cascade,   
   FOREIGN KEY ("Address") REFERENCES Table2("Address") on delete cascade on update cascade
);

Cette définition indique à PostgreSQL à peu près ce qui suit: "Créez une table avec quatre colonnes, l'une sera la clé primaire (PK), les autres le seront NULL. Si une nouvelle ligne est insérée, cochez DataIDet Address: si elles contiennent une valeur non NULL ( disons 27856), puis Table1recherchez DataID˙et Table2pour Address. S'il n'y a pas une telle valeur dans ces tables, renvoyez une erreur. " Ce dernier point que vous avez vu en premier:

ERROR: insert or update on table "Table3" violates foreign key constraint 
    "Table3_DataID_fkey" DETAIL: Key (DataID)=(27856) is not present in table "Table1".

Si simple: s'il n'y a pas de ligne dans Table1DataID = 27856, vous ne pouvez pas insérer cette ligne dans Table3.

Si vous avez besoin de cette ligne, vous devez d' abord insérer une ligne dans Table1avec DataID = 27856, puis essayer ensuite de l'insérer dans Table3. Si cela ne vous semble pas ce que vous voulez, veuillez décrire en quelques phrases ce que vous voulez réaliser, et nous pouvons vous aider avec une bonne conception.


Et maintenant sur les autres problèmes.

Vous définissez vos PK comme

CREATE all_your_tables (
    first_column NOT NULL DEFAULT '0',   
    [...]
    PRIMARY KEY ("ID"),  

Une clé primaire signifie que tous les éléments qu'elle contient sont différents les uns des autres, c'est-à-dire que les valeurs sont UNIQUE. Si vous donnez une statique DEFAULT(comme '0') à une UNIQUEcolonne, vous rencontrerez constamment de mauvaises surprises. C'est ce que vous avez obtenu dans votre troisième message d'erreur.

En outre, '0'signifie une chaîne de texte, mais pas un nombre ( bigintou numericdans votre cas). Utilisez simplement à la 0place (ou ne l'utilisez pas du tout, comme je l'ai écrit ci-dessus).

Et un dernier point (je peux me tromper ici): dans Table2, votre Addresschamp est défini sur numeric(20). En même temps, c'est le PK de la table. Le nom de la colonne et le type de données suggèrent que cette adresse peut changer à l'avenir. Si c'est vrai, c'est un très mauvais choix pour un PK. Pensez au scénario suivant: vous avez une adresse '1234567890454', qui a un enfant Table3comme

ID        DataID           Address             Data
123       3216547          1234567890454       654897564134569

Maintenant, cette adresse passe à quelque chose d'autre. Comment incitez-vous votre enfant à Table3suivre son parent jusqu'à la nouvelle adresse? (Il existe des solutions pour cela, mais peut causer beaucoup de confusion.) Si tel est votre cas, ajoutez une colonne ID à votre table, qui ne contiendra aucune information du monde réel, elle servira simplement de valeur d'identification (c'est-à-dire , ID) pour une adresse.

dezso
la source
Merci pour votre précieuse suggestion. J'essaierai une meilleure conception en fonction de vos suggestions. Maintenant, la première erreur est résolue.
Haseena
0

Tout dépend de ce que vous voulez faire des données.

Premier exemple - vous voulez avoir des données cohérentes dans toutes les tables, mais vous essayez d'insérer des valeurs qui ne correspondent pas à Table1.

Deuxième exemple - vous ne voulez pas avoir de données cohérentes, mais essayez de faire autre chose, sans savoir exactement quoi. La table ne peut pas avoir plus d'une clé primaire.

Troisième exemple - vous ne savez toujours pas ce que vous voulez réaliser et mettez une contrainte UNIQUE sur une colonne qui peut avoir plusieurs fois la même valeur.

Si vous souhaitez simplement insérer vos données, supprimez les références de clés étrangères dans le premier exemple. Si vous souhaitez avoir des données cohérentes dans toutes les tables, effectuez le nettoyage des données, puis insérez-les dans les tables AVEC des contraintes de clé étrangère.

tl; dr: pour insérer vos données dans Table3 avec le code du premier exemple - insérez les valeurs manquantes dans la colonne Table1.DataID qui existent dans Table3.DataId.

BartekR
la source