postgresqldatabase-design

How do I preserve data integrity with a linking table in PostgreSQL?


I have these tables in my PostgreSQL database:

CREATE TABLE companies (
    id INT PRIMARY KEY,
    name VARCHAR(255) NOT NULL UNIQUE
);

-- Employees belong to one company
CREATE TABLE employees (
    id INT PRIMARY KEY,
    companyId INT NOT NULL,
    employeeName VARCHAR(255) NOT NULL,
    FOREIGN KEY (companyId) REFERENCES companies(id)
);

-- Projects Belong to one company
CREATE TABLE projects (
    id INT PRIMARY KEY,
    companyId INT NOT NULL,
    projectName VARCHAR(255) NOT NULL,
    FOREIGN KEY (companyId) REFERENCES companies(id)
);

Now I need to create a table that links an employee to a project:

-- The linking table (with the problem)
CREATE TABLE assignments (
    id INT PRIMARY KEY,
    employeeId INT NOT NULL,
    projectId INT NOT NULL,
    FOREIGN KEY (employeeId) REFERENCES employees(id),
    FOREIGN KEY (projectId) REFERENCES projects(id)
);

The issue is that an employee from one company, can be linked to a project from another company, which I do not want.

How do I enforce the employee and project to be from the same company?


Solution

  • The clean SQL solution is to add redundant unique constraints that include the companyid to projects and employees and reference those with the foreign keys:

    ALTER TABLE projects ADD UNIQUE (companyid, id);
    
    ALTER TABLE employees ADD UNIQUE (companyid, id);
    
    CREATE TABLE assignments (
        id INT PRIMARY KEY,
        employeeid INT NOT NULL,
        projectid INT NOT NULL,
        companyid INT NOT NULL,
        FOREIGN KEY (companyid, employeeid) REFERENCES employees(companyid, id),
        FOREIGN KEY (companyid, projectid) REFERENCES projects(companyid, id)
    );
    

    The extra unique index is of course painful, but a consolation is that you should have an index on companyid anyway if you ever want to delete a row in companies.