Question

This is how I have structured my tables. The tables are AGENT, OFFICE, TRAINING respectively. Same as the question line, is the following table in 3NF? Is it bad practice to have 2 FK?

Things are fine when we assume each office only has one agent or that each agent only has one training. When I look into offices having more than 1 agent and agents having more than 1 training, it becomes messy and no longer 3NF. The first set of table are with no repetitions. The second set displays the repetitions. Please advice. Thanks.

No repetition:

1

Same tables but information repetition:

enter image description here

Was it helpful?

Solution

To easiest way to get to 3NF is by applying Entity Relationship Modeling methodology

  1. Identify the entities
  2. Identify the relationships between the entities
  3. Determine the cardinality of each relationship (e.g. one-to-zero_or_one, one-to-many, many-to-many, etc.) in each direction of the relationship.

The cardinality of each relationship will reveal which side of the relationship should get a foreign key, or whether an additional table should be added to resolve a many-to-many relationship.

For example, if an office can have more than one agent, but an agent can be related to at most one office, then the foreign key would be an office_id column on the agent table. If an agent can be related to more than one office, and and office can have more than one agent, then add a third table agent_office which has two foreign keys, office_id and agent_id each referencing one of the related tables (office and agent, respectively.)

Assuming:

Entities:

  • office
  • agent
  • training

Relationships:

  • an agent can be related to zero, one or more offices
  • an office can be related to zero, one or more agents
  • an agent can be related to zero, one or more training
  • a training can be related to zero, one or more agent

CREATE TABLE office
( id INT UNSIGNED PRIMARY KEY COMMENT 'PK'
, ...
)

CREATE TABLE agent
( id INT UNSIGNED PRIMARY KEY COMMENT 'PK'
, ...
)

CREATE TABLE training
( id INT UNSIGNED PRIMARY KEY COMMENT 'PK'
, ...
)

To resolve the many-to-many relationship between agent and office:

 CREATE TABLE agent_office
 ( agent_id INT UNSIGNED COMMENT 'composite PK, FK ref agent.id'
 , office_id INT UNSIGNED COMMENT 'composite PK, FK ref office.id'
 , PRIMARY KEY (agent_id, office_id)
 , CONSTRAINT FK_agent_office_agent FOREIGN KEY (agent_id) REFERENCES agent (id)
 , CONSTRAINT FK_agent_office_office FOREIGN KEY (office_id) REFERENCES office (id)
 )

Similarly for the many-to-many relationship between agent and training, we add another table:

 CREATE TABLE agent_training
 ( agent_id INT UNSIGNED COMMENT 'composite PK, FK ref agent.id'
 , training_id INT UNSIGNED COMMENT 'composite PK, FK ref training.id'
 , PRIMARY KEY (agent_id, training_id)
 , CONSTRAINT FK_agent_training_agent FOREIGN KEY (agent_id) REFERENCES agent (id)
 , CONSTRAINT FK_agent_training_training FOREIGN KEY (training_id) REFERENCES training (id)
 )

In some edge cases, there may not be a unique constraint on the (agent_id,office_id) tuple, especially when we consider retaining temporal data. (For example, if we need to track that agent 99 was assigned to Office 7 from 2009 thru 2011, and was again assigned to Office 7 starting in 2013.) But if all that we need our model to answer is whether an agent is "assigned" to a particular office or not, then we can have a unique constraint on the (agent_id, office_id) tuple.

In terms of "training", is that a particular training course (e.g. "Sensitivity"), and what if agent 86 repeatedly attends the same "training". Then likely we would have a "training_session" table, related to a "training course", but offered at a particular time and location. Then we'd probably instead have a relationship "agent attended training_session".


Anyways, this Entity Relationship Modeling methodology is the quickest way to get to a 3NF model.

The opinion comes in on whether implementing a purely 3NF model is the most appropriate for a particular application. Denormalizing the model from 3NF, that is, introducing controlled redundancy, effectively "breaks" 3NF, and is quite suitable for some applications, primarily because it provides some performance benefits, and can make some code simpler.

The key here is that we are AWARE of the redundancy, that the database implementation is NOT 3NF, and the application implements logic that controls/manages the redundancy.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top