Thread: foreign keys constraints, depending on each other
I was just creating this little database for demonstrating the use of foreign keys constraints. I was about the create 3 tables, namely mother, father and child. Mother has a foreign key pointing at father ( id ), and father has a foreign key pointing at mother ( id ). Child has one pointer to mother ( id ) and one pointer to father ( id ). How can I prevent the error message from occurring? Ofcourse I see the problem here... just by taking away the references keyword from the mother table takes away the problem completely. --- DROP SEQUENCE mother_id_seq; DROP SEQUENCE father_id_seq; DROP SEQUENCE child_id_seq; DROP TABLE mother; DROP TABLE father; DROP TABLE child; CREATE TABLE mother ( id SERIAL, fatherID INT4 NOT NULL REFERENCES father ( id ) ON DELETE CASCADE, name TEXT, UNIQUE ( fatherID ) ); CREATE TABLE father ( id SERIAL, motherID INT4 NOT NULL REFERENCES mother ( id ) ON DELETE CASCADE, name TEXT, UNIQUE ( motherID ) ); CREATE TABLE child ( id SERIAL, motherID INT4 NOT NULL REFERENCES mother ( id ) ON DELETE CASCADE, fatherID INT4 NOT NULL REFERENCES father ( id ) ON DELETE CASCADE, name TEXT ); --- Thanks Daniel Akerud
On Sun, 10 Jun 2001 zilch@home.se wrote: > > I was just creating this little database for demonstrating the use of > foreign keys constraints. > > I was about the create 3 tables, namely mother, father and child. Mother has > a foreign key pointing at father ( id ), and father has a foreign key > pointing at mother ( id ). Child has one pointer to mother ( id ) and one > pointer to father ( id ). How can I prevent the error message from occurring? You don't put the constraint at table creation time. The table referenced by the references has to exist. Use ALTER TABLE to add the constraint after creating table father.
> > I was just creating this little database for demonstrating the use of > > foreign keys constraints. > > > > I was about the create 3 tables, namely mother, father and child. Mother has > > a foreign key pointing at father ( id ), and father has a foreign key > > pointing at mother ( id ). Child has one pointer to mother ( id ) and one > > pointer to father ( id ). How can I prevent the error message from occurring? > > You don't put the constraint at table creation time. The table referenced > by the references has to exist. Use ALTER TABLE to add the constraint > after creating table father. > I tried: BEGIN; SET CONSTRAINTS ALL DEFERRED; INSERT INTO mother (fatherID, name) VALUES ( 1, 'mamma' ) ; INSERT INTO father (motherID, name) VALUES ( 1, 'pappa' ) ; INSERT INTO child (motherID, fatherID, name) VALUES (1, 1, 'barn 1') ; INSERT INTO child (motherID, fatherID, name) VALUES (1, 1, 'barn 2') ; COMMIT; ...which did not work. Still it complains about key referenced from mother not found in father. --- Daniel Akerud
On Sun, 10 Jun 2001 zilch@home.se wrote: > > > > I was just creating this little database for demonstrating the use of > > > foreign keys constraints. > > > > > > I was about the create 3 tables, namely mother, father and child. Mother has > > > a foreign key pointing at father ( id ), and father has a foreign key > > > pointing at mother ( id ). Child has one pointer to mother ( id ) and one > > > pointer to father ( id ). How can I prevent the error message from occurring? > > > > You don't put the constraint at table creation time. The table referenced > > by the references has to exist. Use ALTER TABLE to add the constraint > > after creating table father. > > > > I tried: > > BEGIN; > SET CONSTRAINTS ALL DEFERRED; > INSERT INTO mother (fatherID, name) VALUES ( 1, 'mamma' ) ; > INSERT INTO father (motherID, name) VALUES ( 1, 'pappa' ) ; > INSERT INTO child (motherID, fatherID, name) VALUES (1, 1, 'barn 1') ; > INSERT INTO child (motherID, fatherID, name) VALUES (1, 1, 'barn 2') ; > COMMIT; > > ...which did not work. Still it complains about key referenced from mother not > found in father. Ah, that's because you didn't define the constraints DEFERRABLE. SET CONSTRAINTS ALL DEFERRED only changes the state of deferrable constraints. If you don't specify a time, it's INITIALLY IMMEDIATE. If it's initially immediate, it's NOT DEFERRABLE unless DEFERRABLE is explicitly given.
On Sun, 10 Jun 2001 zilch@home.se wrote: > I was about the create 3 tables, namely mother, father and child. Mother has > a foreign key pointing at father ( id ), and father has a foreign key > pointing at mother ( id ). Child has one pointer to mother ( id ) and one > pointer to father ( id ). How can I prevent the error message from occurring? Personnally, I tend to avoid those circular references in any computing field. I would remove the father and mother references, and add a is_married relation; as a table, with a UNIQUE(father_id), UNIQUE(mother_id) constraint (a person can be only married once). I would keep the direct references from child. It might a bit diminush the performance, but circular references are a pain to handle. Alternatively, keep only the mother -> father reference, and determine the wife of father through query like: SELECT m.id FROM mother m WHERE m.father_id = ? This can be quite efficient if the mother was looked up previously anyway.
On Mon, 11 Jun 2001, Mario Weilguni wrote: > > relation; as a table, with a UNIQUE(father_id), UNIQUE(mother_id) > > constraint (a person can be only married once). > > Is not true, at least not in some arabic countries. in that case my model is even better since it *allows* for that case (by removing the UNIQUE constraints), where the REFERENCES model has an issue.
> > > relation; as a table, with a UNIQUE(father_id), UNIQUE(mother_id) > > > constraint (a person can be only married once). > > > > Is not true, at least not in some arabic countries. > > in that case my model is even better since it *allows* for that case (by > removing the UNIQUE constraints), where the REFERENCES model has an issue. ( =) ) Thanks for the tip! I think i think i'll use that one... Daniel Akerud
On Sun, 10 Jun 2001 zilch@home.se wrote: > Ofcourse I see the problem here... just by taking away the references > keyword from the mother table takes away the problem completely. Your problem isn't just one of references. Your inherant table design is flawed. If you go by a strict relationship pairing, fatherid and motherid should only be paired once. You can get less tables if you use this structure, similar to a geneology system: --- DROP SEQUENCE seq_personid; DROP SEQUENCE seq_relationid; DROP TABLE person; DROP TABLE relation; CREATE TABLE person ( personid INTEGER NOT NULL DEFAULT NEXTVAL('seq_personid'), first VARCHAR(50) NOT NULL, middle VARCHAR(50), last VARCHAR(50) NOT NULL, birthdate DATETIME NOT NULL, sex CHAR(1) NOT NULL, CONSTRAINT pk_person PRIMARY KEY (personid) ); CREATE TABLE relation ( relationid INTEGER NOT NULL DEFAULT NEXTVAL('seq_relationid'), firstid INTEGER NOT NULL, secondid INTEGER NOT NULL, reldate DATETIME NOT NULL, reldesc VARHCAR(50) NOT NULL, CONSTRAINT pk_relation PRIMARY KEY (relationid) ); ALTER TABLE relation ADD CONSTRAINT fk_person_personid_1 FOREIGN KEY (firstid) REFERENCES person (personid) ON DELETE CASCADE; ALTER TABLE relation ADD CONSTRAINT fk_person_personid_2 FOREIGN KEY (secondid) REFERENCES person (personid) ON DELETE CASCADE; CREATE SEQUENCE seq_personid INCREMENT 1 MINVALUE 1 MAXVALUE 2147483647 START 1 CACHE 1; CREATE SEQUENCE seq_relationid INCREMENT 1 MINVALUE 1 MAXVALUE 2147483647 START 1 CACHE 1; --- Theoretically, this structure lets you add and subtract parts of your table structure at will without damaging anything. Don't like your constraints for a table load? Remove them temporarily. You might want to also think about making another table to hold the reldesc and key it into relation, since you most likely have a constrained subset of defined relationships: Married, Son, Daughter, etc. Why not drop constraint? Last I checked in postgres 7.0, that is not an allowed operation. I still suggest using this syntax though, since the ability may be added in the future. -- +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+ | Shaun M. Thomas INN Database Programmer | | Phone: (309) 743-0812 Fax : (309) 743-0830 | | Email: sthomas@townnews.com AIM : trifthen | | Web : hamster.lee.net | | | | "Most of our lives are about proving something, either to | | ourselves or to someone else." | | -- Anonymous | +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
Am Montag, 11. Juni 2001 10:25 schrieb Marc SCHAEFER: > I would remove the father and mother references, and add a > is_married > relation; as a table, with a UNIQUE(father_id), UNIQUE(mother_id) > constraint (a person can be only married once). Is not true, at least not in some arabic countries. -- =================================================== Mario Weilguni KPNQwest Austria GmbH Senior Engineer Web Solutions Nikolaiplatz 4 tel: +43-316-813824 8020 graz, austria fax: +43-316-813824-26 http://www.kpnqwest.at e-mail: mario.weilguni@kpnqwest.com ===================================================