Skip site navigation (1) Skip section navigation (2)

Re: foreign key constraint to multiple tables

From: Oliver Elphick <olly(at)lfix(dot)co(dot)uk>
To: Kevin McCarthy <kemccarthy1(at)gmail(dot)com>
Cc: pgsql-novice(at)postgresql(dot)org
Subject: Re: foreign key constraint to multiple tables
Date: 2007-08-14 22:11:50
Message-ID: 1187129510.11237.351.camel@linda.lfix.co.uk (view raw or flat)
Thread:
Lists: pgsql-novice
On Mon, 2007-08-13 at 09:14 -0700, Kevin McCarthy wrote:
> I have a table with a column that will join with one of several tables
> based on the value of another column. I'm not sure if this column can
> be set as a foreign key to any of these tables, may be simply bad
> design on my part. The item_type_id column of a record of 'A' will
> reference one of the 'type' table records depending upon what the
> value of the record's item_type column is. 
> 
> Is there a way to set the item_type_id column in Table A as a foreign
> key to the other tables depending? Or would there be a better way to
> design this schema?
> 
> TIA
> 
> CREATE TABLE ABC(
>  id SERIAL PRIMARY KEY,
>  item_type character varying(10) NOT NULL,
>  item_type_id INTEGER
> );
> 
> CREATE TABLE typeA(
>   typeA_id SERIAL PRIMARY KEY 
> );
> 
> CREATE TABLE typeB(
>   typeB_id SERIAL PRIMARY KEY
> );
> 
> CREATE TABLE typeC(
>   typeC_id SERIAL PRIMARY KEY
> );


You can't use a foreign key directly here, since it has to specify a
single table.

If you only need to check for the existence of a row in one of the three
type* tables, you could create a function returning a boolean result and
call it in a CHECK constraint:

CREATE FUNCTION check_type(varchar(10), integer)
  LANGUAGE plpgsql
  RETURNS boolean
  AS $$
     DECLARE
       tp   ALIAS FOR  $1;
       id   ALIAS FOR  $2;
     BEGIN;
       IF tp = 'A' THEN
          PERFORM * FROM typea WHERE typea_id = id;
       ELSIF tp = 'B' THEN
          PERFORM * FROM typeb WHERE typea_id = id;
       ELSE
          PERFORM * FROM typec WHERE typea_id = id;
       END IF;
       RETURN FOUND;
     END;
  $$;

(Note that a table that you call typeA will be called typea in the
database unless you double-quote the name when creating it.)

CREATE TABLE ABC(
 id SERIAL PRIMARY KEY,
 item_type character varying(10) NOT NULL,
 item_type_id INTEGER,
 CONSTRAINT "correct type"
    CHECK (check_type(item_type, item_type_id))
);


If an update of a type* table has to update rows in ABC, you will need
to create an index table whose primary key is type and id and make a
foreign key from ABC to that.  You would have to create triggers to
update the index table when you insert, update or delete a row in type*.
Alternatively you could set up such triggers directly, without creating
a foreign key reference.


Schema redesign
===============

Is it necessary to have three type tables?  If you have a single id
table, with a type field, you could have a foreign key from ABC to type
and eliminate the type field from ABC.  (If you already have data with
duplicate type ids, you would have to change the data.)
-- 
Oliver Elphick                                          olly(at)lfix(dot)co(dot)uk
Isle of Wight                              http://www.lfix.co.uk/oliver
GPG: 1024D/A54310EA  92C8 39E7 280E 3631 3F0E  1EC0 5664 7A2F A543 10EA
                 ========================================
   Do you want to know God?   http://www.lfix.co.uk/knowing_god.html


-- 
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.


In response to

pgsql-novice by date

Next:From: Richard Broersma JrDate: 2007-08-15 01:49:50
Subject: Re: foreign key constraint to multiple tables
Previous:From: Kevin McCarthyDate: 2007-08-14 21:26:33
Subject: foreign key constraint to multiple tables

Privacy Policy | About PostgreSQL
Copyright © 1996-2014 The PostgreSQL Global Development Group