简体   繁体   中英

postgresql no unique constraint error

I get for this schema this error:

ERROR:  there is no unique constraint matching given keys for referenced table "abteilung"

What I am doing wrong? EDIT: now I add a column krankenhaus to the table mitarbeiter and change the alter table command but I get the same error...

SCHEMA:

CREATE TABLE Person (
    svnr VARCHAR(40) PRIMARY KEY,
    anschrift VARCHAR(40) NOT NULL,
    name VARCHAR(20) NOT NULL
);

BEGIN;

CREATE TABLE Mitarbeiter (
    svnr VARCHAR(40) PRIMARY KEY REFERENCES Person(svnr),
    beschaeftigt_seit DATE NOT NULL,
    gehalt NUMERIC(5,2),
    CHECK(gehalt > 0),
    abteilung INTEGER NOT NULL,
    krankenhaus INTEGER NOT NULL
);

CREATE TABLE Krankenhaus (
    kid INTEGER PRIMARY KEY DEFAULT nextval('seq_krankenhaus'),
    anschrift VARCHAR(40) NOT NULL,
    name VARCHAR(20) NOT NULL,
    geleitet_von VARCHAR(40) REFERENCES Mitarbeiter(svnr) DEFERRABLE INITIALLY DEFERRED
);

CREATE TABLE Abteilung (
    abid INTEGER DEFAULT nextval('seq_abteilung'),
    name VARCHAR(40) NOT NULL,
    anschrift VARCHAR(40) NOT NULL,
    koordiniert VARCHAR(40) REFERENCES Mitarbeiter(svnr) DEFERRABLE INITIALLY DEFERRED,
    krankenhaus INTEGER REFERENCES Krankenhaus(kid),
    PRIMARY KEY (abid, krankenhaus)
);

ALTER TABLE Mitarbeiter ADD CONSTRAINT fk_abteilung FOREIGN KEY (abteilung, krankenhaus) REFERENCES Abteilung(abid, krankenhaus) DEFERRABLE INITIALLY DEFERRED;

COMMIT;

The primary key of the table Abteilung is (abid, krankenhaus) . As a foreign references references exactly one row, you also need to use both columns in the foreign key constraint definition.

But as you don't have a column krankenhaus in your table Mitarbeiter you can't reference Abteilung .

You either need to reduce the primary key of Abteilung to (abid) (which would be possible as it is a generated, artificial key anyway) or add a column Krankenhaus to your Mitarbeiter table.

This should work:

CREATE TABLE person (
   svnr text PRIMARY KEY
 , anschrift text NOT NULL
 , name text NOT NULL
);

CREATE TABLE mitarbeiter (
   svnr text PRIMARY KEY REFERENCES person
 , beschaeftigt_seit date NOT NULL
 , gehalt numeric(5,2)
 , abid int NOT NULL
 , CHECK(gehalt > 0)
);

CREATE TABLE krankenhaus (
   kid serial PRIMARY KEY
 , anschrift text NOT NULL
 , name text NOT NULL
 , geleitet_von text REFERENCES mitarbeiter(svnr) DEFERRABLE INITIALLY DEFERRED
);

CREATE TABLE abteilung (
   abid serial PRIMARY KEY
 , kid INTEGER REFERENCES krankenhaus(kid)
 , koordiniert text REFERENCES mitarbeiter(svnr) DEFERRABLE INITIALLY DEFERRED
 , name text NOT NULL
 , anschrift text NOT NULL
);

ALTER TABLE mitarbeiter
   ADD CONSTRAINT fk_abteilung FOREIGN KEY (abid)
   REFERENCES abteilung(abid) DEFERRABLE INITIALLY DEFERRED;

Major points

  • Use a serial column for surrogate PKs:

  • Don't use varchar(n) with arbitrary limitations for string length, unless you really need to enforce a maximum length and its not going to change. Details:

  • Go with just abid as primary key for abteilung . There would be a related application for a redundant column included in a FK constraint, but that's not what your model does right now:

  • No need to use an explicit transaction ( BEGIN ... COMMIT ) for part of the code.

  • The real difficulty with this kind of circular reference is entering and changing data. You probably made your FK constraints DEFERRABLE INITIALLY DEFERRED - which is going to make some queries considerably slower .
    You could go with just plain default IMMEDIATE FK constraints, if you wrap INSERT / UPDATE on related rows into data-modifying CTEs :

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM