Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>First, your example tables are doing too much. There is a design principle that states that a single table should model an entity or a relationship between entities but not both. The relationships between departments, directors and employees (I'm assuming that directors are not employees; I'm also omitting divisions for the moment).</p> <p>Second, a table can have more than one key, known as candidate keys. Further, you can create a <code>UNIQUE</code> constraint by 'appending' a non-unique column to a key. For example, employees' names do not make for a good key, hence the reason for having an employee ID (I don't think the same can be said for departments i.e. department name in itself is a good enough key). If <code>employee_ID</code> is unique then it follows that <code>(employee_name, employee_ID)</code> will also be unique.</p> <p>Third, a table can be referenced by any <code>UNIQUE</code> constraint, it doesn't have to be the table's 'primary' key (which partly explains why 'primary key' is a bit of a nonsense).</p> <p>The great thing about the above is that one can model the required constraints using <code>FOREIGN KEY</code> and row-level <code>CHECK</code> constraints. SQL optimizers and programmers prefer declarative solutions to procedural code (triggers, stored procs, etc). This vanilla SQL DDL will port to most SQL products.</p> <p>So, the department name can be combined with both the director key and the employee key respectively and these compound keys can be referencesd in a simple two-tier org chart table: because both the employee's department and their director's department will appear in the same table, a simple row-level <code>CHECK</code> constraint can be used to test that they are the same e.g.</p> <p>Entity tables: </p> <pre><code>CREATE TABLE Departments ( department_name VARCHAR(30) NOT NULL UNIQUE ); CREATE TABLE Employees ( employee_ID INTEGER NOT NULL UNIQUE, employee_name VARCHAR(100) NOT NULL ); CREATE TABLE Directors ( director_ID INTEGER NOT NULL UNIQUE, director_name VARCHAR(100) NOT NULL ); </code></pre> <p>Relationship tables:</p> <pre><code>CREATE TABLE EmployeeDepartments ( employee_ID INTEGER NOT NULL UNIQUE REFERENCES Employees (employee_ID), employee_department_name VARCHAR(30) NOT NULL REFERENCES Departments (department_name), UNIQUE (employee_department_name, employee_ID) ); CREATE TABLE DirectorDepartments ( director_ID INTEGER NOT NULL UNIQUE REFERENCES Directors (director_ID), director_department_name VARCHAR(30) NOT NULL REFERENCES Departments (department_name), UNIQUE (director_department_name, director_ID) ); CREATE TABLE OrgChart ( employee_ID INTEGER NOT NULL UNIQUE, employee_department_name VARCHAR(30) NOT NULL, FOREIGN KEY (employee_department_name, employee_ID) REFERENCES EmployeeDepartments (employee_department_name, employee_ID), director_ID INTEGER NOT NULL, director_department_name VARCHAR(30) NOT NULL, FOREIGN KEY (director_department_name, director_ID) REFERENCES DirectorDepartments (director_department_name, director_ID), CHECK (employee_department_name = director_department_name) ); </code></pre> <p>Now a slightly more interesting scenario would be when a director is assigned a division, rather than a specific department, and you had to test that the employee's department was in the same division as her director:</p> <p>Entity tables:</p> <pre><code>CREATE TABLE Divisions ( division_name VARCHAR(20) NOT NULL UNIQUE ); CREATE TABLE Departments ( department_name VARCHAR(30) NOT NULL UNIQUE, division_name VARCHAR(20) NOT NULL REFERENCES Divisions (division_name), UNIQUE (division_name, department_name) ); CREATE TABLE Employees ( employee_ID INTEGER NOT NULL UNIQUE, employee_name VARCHAR(100) NOT NULL ); CREATE TABLE Directors ( director_ID INTEGER NOT NULL UNIQUE, director_name VARCHAR(100) NOT NULL ); </code></pre> <p>Relationship tables:</p> <pre><code>CREATE TABLE EmployeeDepartments ( employee_ID INTEGER NOT NULL UNIQUE REFERENCES Employees (employee_ID), employee_department_name VARCHAR(30) NOT NULL REFERENCES Departments (department_name), UNIQUE (employee_department_name, employee_ID) ); CREATE TABLE DirectorDivisions ( director_ID INTEGER NOT NULL UNIQUE REFERENCES directors (director_ID), director_division_name VARCHAR(20) NOT NULL REFERENCES divisions (division_name), UNIQUE (director_division_name, director_ID) ); CREATE TABLE OrgChart ( employee_ID INTEGER NOT NULL UNIQUE, employee_department_name VARCHAR(30) NOT NULL, FOREIGN KEY (employee_department_name, employee_ID) REFERENCES EmployeeDepartments (employee_department_name, employee_ID), employee_division_name VARCHAR(20) NOT NULL REFERENCES divisions (division_name), FOREIGN KEY (employee_division_name, employee_department_name) REFERENCES Departments (division_name, department_name), director_ID INTEGER NOT NULL, director_division_name VARCHAR(20) NOT NULL, FOREIGN KEY (director_division_name, director_ID) REFERENCES DirectorDivisions (director_division_name, director_ID), CHECK (employee_division_name = director_division_name) ); </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload