Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple yet mutually exclusive foreign keys - is this the way to go?

I have three tables: Users, Companies and Websites. Users and companies have websites, and thus each user record has a foreign key into the Websites table. Also, each company record has a foreign key into the Websites table.

Now I want to include foreign keys in the Websites table back into their respective "parent" records. How do I do that? Should I have two foreign keys in each website record, with one of them always NULL? Or is there another way to go?

like image 634
Sleepster Avatar asked Sep 29 '09 15:09

Sleepster


People also ask

Can a foreign key appear multiple times?

a) Yes you can. B) composite key would need to contain date or something to guarantee uniqueness in your customerHoliday association but not enough information is provided to figure it out. (a) is fine: you can have as many entities as you want referencing the same foreign key.

Does the foreign key go on the one or many side?

Whichever one is not the primary key is the foreign key. In one-to-many relationships, the FK goes on the "many" side. It can't go on the "one" side because that's where the PK goes and the definition of a primary key includes disallowing duplicates.


2 Answers

If we look into the model here, we will see the following:

  1. A user is related to exactly one website
    • A company is related to exactly one website
    • A website is related to exactly one user or company

The third relation implies existence of a "user or company" entity whose PRIMARY KEY should be stored somewhere.

To store it you need to create a table that would store a PRIMARY KEY of a website owner entity. This table can also store attributes common for a user and a website.

Since it's a one-to-one relation, website attributes can be stored in this table too.

The attributes not shared by users and companies should be stored in the separate table.

To force the correct relationships, you need to make the PRIMARY KEY of the website composite with owner type as a part of it, and force the correct type in the child tables with a CHECK constraint:

CREATE TABLE website_owner (
    type INT NOT NULL,
    id INT NOT NULL,
    website_attributes,
    common_attributes,
    CHECK (type IN (1, 2)) -- 1 for user, 2 for company
    PRIMARY KEY (type, id)
)

CREATE TABLE user (
    type INT NOT NULL,
    id INT NOT NULL PRIMARY KEY,
    user_attributes,
    CHECK (type = 1),
    FOREIGN KEY (type, id) REFERENCES website_owner
)

CREATE TABLE company (
    type INT NOT NULL,
    id INT NOT NULL PRIMARY KEY,
    company_attributes,
    CHECK (type = 2),
    FOREIGN KEY (type, id) REFERENCES website_owner
)
like image 159
Quassnoi Avatar answered Sep 22 '22 19:09

Quassnoi


you don’t need a parent column, you can lookup the parents with a simple select (or join the tables) on the users and companies table. if you want to know if this is a user or a company website i suggest using a boolean column in your websites table.

like image 32
knittl Avatar answered Sep 23 '22 19:09

knittl