Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PostgreSQL foreign key not existing, issue of inheritance?

I am struggling with foreign keys in my DB, possibly it has something to do with inheritance?
So here's the basic setup:

-- table address
CREATE TABLE address
(
  pk_address serial NOT NULL,
  fk_gadmid_0 integer NOT NULL, -- this table already exists, no problem here
  street character varying(100),
  zip character varying(10),
  city character varying(50),
  public boolean,
  CONSTRAINT address_primarykey PRIMARY KEY (pk_address),
  CONSTRAINT gadmid_0_primarykey FOREIGN KEY (fk_gadmid_0)
      REFERENCES adm0 (gadmid_0) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE NO ACTION
)
WITH (
  OIDS=FALSE
);
ALTER TABLE address OWNER TO postgres;  

-- table stakeholder (parent)
CREATE TABLE stakeholder
(
    pk_stakeholder integer DEFAULT nextval('common_stakeholder_seq') NOT NULL,
    fk_stakeholder_type integer NOT NULL, -- this table also exists, no problem here
    name character varying(255) NOT NULL,
    CONSTRAINT stakeholder_primarykey PRIMARY KEY (pk_stakeholder),
    CONSTRAINT stakeholder_fk_stakeholder_type FOREIGN KEY (fk_stakeholder_type)
        REFERENCES stakeholder_type (pk_stakeholder_type) MATCH SIMPLE
        ON UPDATE CASCADE ON DELETE NO ACTION
)
WITH (
    OIDS=FALSE
);
ALTER TABLE stakeholder OWNER TO postgres;  

-- table individual (child of stakeholder)
CREATE TABLE individual
(
    firstname character varying(50),
    fk_title integer, -- this table also exists, no problem here
    email1 character varying (100),
    email2 character varying (100),
    phone1 character varying (50),
    phone2 character varying (50),
    CONSTRAINT individual_primarykey PRIMARY KEY (pk_stakeholder),
    CONSTRAINT title_foreignkey FOREIGN KEY (fk_title)
        REFERENCES title (pk_title) MATCH SIMPLE
        ON UPDATE CASCADE ON DELETE CASCADE
) INHERITS (stakeholder)
WITH (
    OIDS=FALSE
);
ALTER TABLE individual OWNER TO postgres;  

-- link between stakeholder and address
CREATE TABLE l_stakeholder_address
(
    pk_l_stakeholder_address serial NOT NULL,
    fk_stakeholder integer NOT NULL REFERENCES stakeholder,
    fk_address integer NOT NULL REFERENCES address,
    CONSTRAINT l_stakeholder_address_primarykey PRIMARY KEY (pk_l_stakeholder_address),
    CONSTRAINT l_stakeholder_address_fk_stakeholder FOREIGN KEY (fk_stakeholder)
        REFERENCES stakeholder (pk_stakeholder) MATCH SIMPLE
        ON UPDATE CASCADE ON DELETE NO ACTION,
    CONSTRAINT l_stakeholder_address_fk_address FOREIGN KEY (fk_address)
        REFERENCES address (pk_address) MATCH SIMPLE
        ON UPDATE CASCADE ON DELETE NO ACTION
)
WITH (
    OIDS=FALSE
);
ALTER TABLE l_stakeholder_address OWNER TO postgres;

So far, no problem. Then I tried to add some values:

INSERT INTO individual (pk_stakeholder, fk_stakeholder_type, name, firstname, fk_title, email1, email2, phone1, phone2) 
  VALUES (1, 8, 'Lastname', 'Firstname', 1, '[email protected]', '', '', '');
INSERT INTO address (pk_address, fk_gadmid_0, street, zip, city, public)  
  VALUES (1, 126, 'Address', '', 'City', FALSE);
INSERT INTO l_stakeholder_address (pk_l_stakeholder_address, fk_stakeholder, fk_address)  
  VALUES (DEFAULT, 1, 1);

And finally I end up having an error (SQL state 23503) saying that the key (fk_stakeholder)=(1) is not existing in table "stakeholder".
The first 2 inserts are fine, I can see them in the databases:

stakeholder:
pk_stakeholder | ...
----------------------
1              | ...

address:
pk_address | ...
--------------------
1          | ...

What am I doing wrong? I must admit that I am rather new to PostgreSQL (using 8.4) but I'm not even sure if that is an issue of PG at all, maybe I'm just lacking some basic database design understandings ...
Either way, by now I tried pretty much everything I could think of, I also tried to make the FK deferrable as in PostgreSQL : Transaction and foreign key problem but somehow that doesn't work either.

like image 345
Lukas Avatar asked Feb 02 '23 21:02

Lukas


2 Answers

You can work around it using additional table individual_pks (individual_pk integer primary key) with all primary keys from both parent and child, which will be maintained using triggers (very simple — insert to individual_pks on insert, delete from it on delete, update it on update, if it changes individual_pk).

Then you point foreign keys to this additional table instead of a child. There'll be some small performance hit, but only when adding/deleting rows.

Or forget inheritance and do it the old way - simply one table with some nullable columns.

like image 158
Tometzky Avatar answered Feb 05 '23 16:02

Tometzky


Your analysis is exactly right: It's because of the inheritance. When checking the foreign key, child tables are not considered.

In general, inheritance and foreign keys don't mix well in PostgreSQL. A major problem is that you can't have unique constraints across tables.

Reference

like image 41
Peter Eisentraut Avatar answered Feb 05 '23 17:02

Peter Eisentraut