Databases · 1970 · E. F. Codd

A Relational Model of Data for Large Shared Data Banks

Separate logical data meaning from pointer paths and physical storage through relations and declarative operations.

How to read the original

  1. Read Data Dependencies in Present Systems and identify ordering, indexing, and access-path dependence.
  2. Follow Relational Model and Normal Form before studying the relational operations and redundancy discussion.
  3. Keep mathematical relations distinct from later SQL behavior such as duplicate rows, NULL, and explicit ordering.

Describe facts without prescribing pointer traversal

Codd argues for protecting applications from unnecessary dependence on storage representation and access paths. Relations describe tuples of values, enabling a logical view that need not expose the physical route used to retrieve them. The paper introduces its own normal-form discussion and relational operations; it should not be presented as a complete specification of modern SQL or every later normalization theorem.

Consider original teaching data for a small shop. Customer contains tuples (customer_id,name), and Purchase contains (purchase_id,customer_id,item). Let Customer contain (7,Ada) and (9,Bo). Let Purchase contain (101,7,book), (102,7,pen), and (103,9,book). The question “which customers bought a book?” can be stated by a condition on values rather than by instructions to follow a particular disk pointer chain.

Trace a relational expression

Select Purchase tuples whose item equals book. The intermediate relation contains (101,7,book) and (103,9,book). Join those tuples with Customer on equal customer_id, yielding the corresponding names. Project the name attribute to obtain {Ada,Bo}. Under the mathematical set model, projecting duplicate name values would remove duplicates; names therefore do not necessarily preserve customer identity.

If two distinct customer identifiers both have name Ada, projecting only name merges them in the result. That is not a database error. It follows from the requested attribute and set semantics. If the task is to identify customers, retain customer_id. Logical precision begins with the question and schema, not with whichever output happens to look plausible.

The engine can implement the join by nested loops, a hash table, or an index lookup. These choices can have different costs while producing the same logical relation. Data independence does not mean physical design becomes irrelevant. It means a physical change should not require rewriting the application’s meaning when the logical contract remains unchanged.

Make redundancy and constraints explicit

Suppose every purchase row also repeats the customer’s phone number. If customer_id determines one current phone number, changing that number requires updating all repeated copies. Updating only one row creates inconsistent facts. A separate CustomerContact(customer_id,phone) relation stores the dependency once, while purchases retain only the customer reference.

The decomposition needs a declared constraint: one phone value per customer under this particular model. If customers may have multiple phone numbers, the schema and query must represent that multiplicity. Normalization is not achieved by splitting tables at random. A decomposition can lose relationships or introduce spurious combinations if the relevant dependencies are ignored.

For example, storing only PersonLanguage(person,language) and PersonCity(person,city) cannot reconstruct which language was used in which city. Joining them creates every language-city combination for that person, potentially asserting relationships never observed. The original relation may have encoded a genuine three-way fact. A join is an operation, not a guarantee of semantic truth.

Keep the implementation contract separate

An unordered relation does not promise row order. A test that succeeds only because records happen to be returned in insertion order has leaked a physical assumption into the application. Later SQL systems also use bags by default in many operations and introduce NULL-related semantics; those features need their own precise treatment.

The enduring design discipline is to state keys, domains, dependencies, and desired result relations before choosing storage or access methods. Then test that alternative implementations preserve the logical answer. This approach supports evolution without pretending that schema design, consistency constraints, or query cost disappear.

Reconstruction exercise

A table stores (student,course,instructor,office), with the assumptions that each course has one instructor and each instructor has one office. Show an update anomaly using two rows, then propose relations that store these dependencies without repeating office facts. Explain which keys and foreign-key-like references are needed to reconstruct enrollments. Finally give an example showing why projecting only instructor names can merge distinct people, and state why row order must be requested explicitly in an implementation that offers ordered output.

Worked solution

Rows (Ada,CS1,Lee,R10) and (Bo,CS1,Lee,R10) repeat Lee’s office. Updating only the first to R12 leaves contradictory office values under the assumptions. Use Enrollment(student_id,course_id), Course(course_id,instructor_id), and Instructor(instructor_id,name,office). Course identifiers determine instructors, and instructor identifiers determine the current office; Enrollment references existing students and courses. Joining on those identifiers reconstructs the association without inventing a connection based only on matching display names. Two instructors with identifiers 4 and 8 may both be named Lee, so projecting name alone yields one value under set semantics even though they are distinct people. An unordered relation does not promise presentation order. A system requiring alphabetical or chronological output must specify that ordering separately rather than rely on an index or insertion history that a storage change could alter.

Test the limits and transfer the idea

1. Relational reasoning · allow 40 minutes

Find the tuples a decomposition invents

Let R(A,B,C) = {(1,x,p), (1,y,q), (2,x,q)} under set semantics. Decompose it into its projections on AB and AC, then natural-join those projections. List all result tuples and identify the spurious ones.

Now prove that this decomposition is lossless for every relation satisfying the functional dependency A → B. State both inclusion directions. Explain why a join that happens to work on one sample does not establish a dependency for future data. Treat the dependency theorem as a modern formal exercise connected to Codd's relation model, not as a quotation from the paper.

Get a starting hint

A joined tuple can borrow B and C from different original rows sharing A. If A determines B, that borrowing cannot introduce a different B.

Compare your reasoning with the worked solution

The projections are AB = {(1,x),(1,y),(2,x)} and AC = {(1,p),(1,q),(2,q)}. Their join is {(1,x,p),(1,x,q),(1,y,p),(1,y,q),(2,x,q)}. The new tuples (1,x,q) and (1,y,p) are spurious. Projection discarded which B and C belonged together for A = 1. The original relation does not satisfy A → B because A = 1 appears with both x and y.

For any R, every original tuple appears in the join: both of its projections are present and agree on A. Thus R is a subset of the joined relation. For the reverse inclusion under A → B, take any joined tuple (a,b,c). Its AB pair comes from some original (a,b,c′), and its AC pair comes from some original (a,b′,c). The dependency forces b = b′ because both source tuples share a. Therefore (a,b,c) is precisely the second source tuple and belongs to R. Both inclusions prove equality.

A dependency is a constraint on allowed relation instances, not an inference licensed by a small sample. A present sample might have only one row per A by accident. If future valid data can use the same A with different B values, the proof's premise no longer holds. This exercise makes logical data relationships explicit while leaving indexes, row placement, and query execution plans unspecified, reflecting the separation that motivates the relational model.

Check your reasoning

  • Lists all five join tuples and identifies exactly two spurious tuples.
  • Proves both inclusions using A → B only where needed.
  • Distinguishes an enforced semantic dependency from a coincidental sample pattern.

2. Set algebra and edge cases · allow 45 minutes

Express an all-required-parts query

A supplier universe is S = {a,b,c,d}, required parts are P = {p1,p2}, and deliveries are R = {(a,p1),(a,p2),(b,p1),(c,p2)}. Derive a relational expression returning suppliers that deliver every required part, including a supplier with no deliveries when the required set is empty.

Evaluate the expression for the stated P and for P = empty. Write a Python set implementation and prove why subtracting suppliers with a missing pair implements the universal condition. Explain the error in choosing the candidate universe as only the supplier projection of R.

Get a starting hint

Construct all required supplier-part pairs, subtract delivered pairs, then remove suppliers that occur in the missing-pair relation.

Compare your reasoning with the worked solution

The expression is S minus projection_supplier((S × P) minus R). In the stated example, missing pairs are (b,p2), (c,p1), (d,p1), and (d,p2). Their supplier projection is {b,c,d}, so the answer is {a}.

S = {'a','b','c','d'}
R = {('a','p1'),('a','p2'),('b','p1'),('c','p2')}
def supplies_all(required):
    missing = {(s,p) for s in S for p in required} - R
    return S - {s for s,p in missing}
assert supplies_all({'p1','p2'}) == {'a'}
assert supplies_all(set()) == S

To prove correctness, a supplier survives the subtraction exactly when there is no required p for which (s,p) is absent from R. This is equivalent to saying that for every p in P, (s,p) is in R. When P is empty, the product S × P and the missing-pair set are empty, so all of S survives. This is the ordinary vacuous truth of a universal statement over an empty set.

Using only projection_supplier(R) as the candidate universe silently loses d before the universal condition is checked. That changes the question to which already-observed suppliers satisfy the requirement. Either query can be useful, but they have different contracts. The example uses mathematical sets, no null values, and a known supplier universe; SQL bags, nullable fields, and business rules about inactive suppliers require additional decisions. The algebraic exercise develops the relation model rather than assuming that Codd's 1970 text specifies every later SQL behavior.

Check your reasoning

  • Derives the product-difference-projection expression and returns {a}.
  • Returns all four suppliers for an empty requirement set.
  • Proves the universal condition and identifies the candidate-universe assumption.

Check your understanding

Why can a database replace a nested-loop join with a hash join without changing an application query?

  • Physical execution can change while preserving the declared logical relation.
  • Hash joins always return the same row order.
  • Relations contain machine pointers as their only values.
Explanation

Data independence separates the requested facts from the chosen access method.

Projecting only names merges two customers named Ada under set semantics. What is the best correction when identity matters?

  • Assume names are unique without checking.
  • Retain the customer identifier in the requested result.
  • Depend on row position to identify customers.
Explanation

The result must include the attribute carrying identity rather than a potentially repeated display value.

Original paper and sources

E. F. Codd. A Relational Model of Data for Large Shared Data Banks. Communications of the ACM 13(6), June 1970, pp. 377-387. Linked resource is the full university-hosted article, replacing a publication-summary page.

Read the original paper →

Read the primary paper: University of Pennsylvania