121 3NF

Informally, Third Normal Form, or 3NF, says that a non-key attribute should not depend on another non-key attribute.

Example which violates 3NF

The following relation has the key {emp_id}:

Employee
101,10,Sales 102,10,Sales 103,20,Engineering 104,20,Engineering

Assume the following functional dependencies hold:

  • {emp_id} → {dept_id} because each employee is assigned to one department
  • {dept_id} → {dept_name} because each department identifier has one department name

The repeated department names make the transitive dependency visible.

The same modelling mistake can be written in Predica. The RM-style attribute names become contextual inside the Employee type, so emp_id is written as id:


entity Employee
{
    Integer id;
    Integer dept_id;
    String dept_name;

    key {id};
}

Here dept_name does not depend directly on the key. It depends on another non-key attribute, dept_id, which is being used as an identifier for an unmodelled department.

Writing the dependency as a constraint

If the model is left in this shape, the dependency from department identifier to department name has to be imposed over the containing collection of employees. One way to write it is to say that there is no pair of employees with the same department identifier and different department names:


entity Company
{
    Employee employee*;

    constraints
    {
        let company = this in
            employee.(let e = this in
                company.employee.[
                    dept_id = e.dept_id
                    ∧ dept_name ≠ e.dept_name
                ].Σempty);
    }
}

This constraint is the Predica form of {dept_id} → {dept_name}. It is non-local because the department name is repeated on employee records instead of being a local fact about a department.

Fixing the violation

The fix is to separate the facts about employees from the facts about departments. In relational form, this decomposes the original relation into two relations:

Employee
101,10 102,10 103,20 104,20
Department
10,Sales 20,Engineering

In Predica, the same repair is to model Department explicitly:


entity Department
{
    Integer id;
    String name;

    key {id};
}

entity Employee
{
    Integer id;
    Department dept;

    key {id};
}

entity Company
{
    Department department*;
    Employee employee*;
}

After this repair, the cross-employee FD constraint is no longer needed. The department name is a local attribute of Department, and each employee points to the department they belong to.