Skip to main content
Database Design and Applications

Normalization: Turning Instinct into Certainty

Published: 2026-08-06
Level: postgraduate
Audience: Postgraduate students of database design and applications

Prerequisite Knowledge

This lecture builds on the following concepts from earlier lectures. If any feel unfamiliar, review the linked notes before proceeding.

Previously Covered in This Subject

  • Keys: super key, candidate key, primary key, and foreign key — covered in Lecture 2 (Entity-Relationship Modeling)
  • Multivalued attributes and null entries — covered in Lecture 2 (Entity-Relationship Modeling)
  • The relational model and first normal form — covered in Lecture 3 (From Requirements to the Relational Model)
  • Relational constraints and foreign key delete options — covered in Lecture 3 (From Requirements to the Relational Model)
  • ER-to-relational schema conversion — covered in Lecture 3 (From Requirements to the Relational Model)
  • Relational versus NoSQL and document databases — covered in Lecture 3 (From Requirements to the Relational Model)

4.1 Why Normalization: Four Guidelines for a Good Relation

4.1.1 Why These Guidelines Exist at All

Hook: You can feel when a database design is "off" — but can you prove it is wrong? ER modeling runs on the designer's instinct; normalization is what turns "this design feels right" into "this design is provably better."

Data is the reason any application exists. An airline company needs data to know what its airplanes cost and to decide where to send its planes when a demographic, political, or geopolitical event changes demand. A supply chain company needs to store its data properly so the data makes sense when it is retrieved. An enterprise application, an Android app, a mobile app, or a web app — all of them exist to solve a user's problem, and solving that problem well needs data. So the question is never whether to store data; it is how to store it so that it can be retrieved efficiently, shared concurrently, and trusted.

We could try to program all of that ourselves in Python, Java, or any language we already know. That attempt would fail, or at least become a Herculean task, because a database carries a huge number of requirements, specifications, and constraints. Storing data properly and retrieving it efficiently by hand is exactly why a database management system exists, and why this course is built around one workflow: a client gives us requirements, we turn those requirements into an ER model that connects the client's words to our design, and then we convert the ER diagram into a relational schema, which we later query with SQL.

The recap ends with a confession that frames the entire session: ER modeling is a best-fit model — it runs on the designer's instinct. A relational schema, by contrast, should be judged by something more measurable, because the data sitting between the requirement and the final schema carries no mathematical certainty on its own. Two diagrams can both be "reasonable," and no one can say which is better without a yardstick. The whole point of today's discussion is to replace "this design feels right" with "this design is provably better."

To do that, we need parameters — criteria that tell us whether a given relation is good. Four guidelines capture what a good database relation must satisfy, and the rest of the course on normalization is just the machinery for satisfying them.

The four guidelines for a good relation

  1. Clear semantics — every relation and attribute means one obvious thing, so anyone can read the table without a private decoder ring.
  2. Least redundancy and least update anomalies — store each fact once, so insert, delete, and update operations stay smooth.
  3. Least null values — missing values are a symptom of a schema that does not fit the reality it models.
  4. Least invented rows — combining tables must not create rows that were never really there.

Everything later in this lecture — functional dependencies, first normal form, second normal form, third normal form, BCNF — exists to make these four guidelines measurable and achievable.

The repeated advice in this session: when you meet any rule, ask why. You can write "WHY" in your notebook and hold the class to it. Understand why a rule exists, and even if you forget how to apply it, you can look it up or re-derive it; if you only memorize the application, you cannot adapt it. Books have been wrong in the past, and they need to be updated for current situations — another reason understanding the "why" matters more than memorizing the "how."

Exam note: Normalization is the answer to a specific problem: ER design leaves too much to the designer's guts, whims, and feelings. The four guidelines are the measurable criteria a good relation must satisfy, and functional dependencies are the formal tool that will deliver them. If an exam question asks "what are the four guidelines for a good relation?" — semantics, minimal redundancy and update anomalies, minimal nulls, and minimal spurious tuples — this is the section it comes from.

4.1.2 Guideline 1: Clear Semantics

A database is a collection of data about a mini world — a slice of reality. The mini world can be an organization, a school, a railway reservation system, an airline reservation system, a university, a supply chain, a healthcare system, a bank, or whatever domain we are modeling. The relations inside that mini world should be self-explanatory: if I create an EMPLOYEE relation with attributes employee ID, employee name, employee phone number, employee email, and address, the semantics are clear. The name of the relation says employee; the attributes say what we store about an employee. There is minimal ambiguity, and anyone who sees the table can make sense of it.

Compare that with the inside of your own room. You know which cupboard holds your books, which holds your clothes, and which holds your utilities. But your knowledge is private: you would have to open every box and every wardrobe to find anything, unless each one carries a label. Clear semantics means putting labels on the boxes — designing tables whose names and attributes speak for themselves.

Q: Why should we bother with good semantics? If I designed the database, I already know which box holds what.

A: You do — but you are not the only person involved. When you move to another company or another project, the next person must be able to tell that this box is for books and this relation is for employees. In any organization, the designer, the users, and the maintainers are different people, often hundreds of them. Unless the table speaks for itself, they cannot query it, debug it, or improve it.

Why does a label matter? Two students worked through the answer in class. The first answer was about personal efficiency: if we know which box holds what, we go directly to it and save time. The discussion pushed back: that only helps the person who designed the room. The second answer was the bullseye: someone else will use it. In any organization, no single person designs, uses, or maintains the software. A database designer is one member of a team; the people using the application query the database; a separate team maintains it after launch; a product built for 20 years must be solid and valuable to people who never met its original designer. If the stored data does not speak for itself — if the semantics are not clear — the team cannot query it, cannot find bugs, and cannot improve it. Clear semantics is not aesthetics; it is the condition that lets hundreds of people work on one database over decades.

4.1.3 Guideline 2: Least Redundancy and Least Update Anomalies

The second guideline: redundancy should be as small as possible, and tuples should have as few update anomalies as possible. Here update is a broad word: update means insert, delete, and modification.

What is an anomaly? Before anyone looks up a dictionary definition, the discussion started from the felt sense of the word. Some students associate it with an outlier — the gifted player in sports, the single student who scores 100 when the class average is 50 (or the one who scores 0), or the outliers we deliberately exclude when training a machine learning model. That association is wrong, and getting it right matters.

Q: What is an anomaly, actually? People use the word for outliers — the gifted sports player, or the data point we exclude when training a model.

A: That usage is not the database meaning. An anomaly is not an outlier; it is a discrepancy, an inconsistency, an irregularity — something that breaks a pattern. In the database world, anomalies are the inconsistencies that prevent us from inserting, updating, or deleting cleanly, and redundancy is their main root cause (foreign key constraints are another). We must avoid them because they block operations and destroy trust in the data.

One student's phrasing earned an approving echo: an anomaly is anything that does not follow some pattern. In the database world, the anomalies that matter are the inconsistencies that prevent us from inserting, from deleting, or from modifying data cleanly. There are three classic kinds:

  • Insert anomaly — we cannot add a row because some required fact does not exist yet (a work assignment cannot be inserted before the project it references exists).
  • Delete anomaly — removing a row silently destroys information that lived only in that row.
  • Update anomaly — changing one fact forces us to hunt down and edit the same value in many places.

The root cause of most anomalies is redundancy, though not all of them: foreign key constraints also restrict insertion, deletion, and modification, as we know from the constraint discussion. Redundancy matters for two reasons. First, wasted space: storing the same thing twice consumes hard disk or storage. (Storage has become cheap, so today this alone would not justify the fuss — but when the relational model was formed, it mattered.) Second, and far more important, consistency: if the same fact is stored in two places and an update touches only one of them, we can no longer be certain which copy is the correct one, and we cannot take decisions on uncertain data.

Worked example — the update anomaly (project rename)

Consider a badly made relation with attributes employee number, project number, employee name, project name, and number of hours. Suppose a separate PROJECT relation stores project number and project name, so the pair (project number, project name) is really one fact. Now the project named Billing is renamed Customer Accounting. The project number and everything else stay the same. But because the project name is repeated inside the employee–project relation, the change must be repeated everywhere the name appears.

Let us count the cost concretely:

  • 1 employee on the project → 1 edit.
  • 100 employees on the project → 100 edits, in 100 different rows.
  • If we miss one of the 100 → the database now contains two different names for the same project, and nobody can say which one is true.

This is an update anomaly: the design prevents a seamless update, and the friction costs time, affects decisions, and degrades output. The fix, seen later in this lecture, is to store project name once — in its own relation — so a rename is a single edit.

Insert and delete anomalies follow the same logic through foreign keys. The project number inside the employee–project relation is a foreign key referring to the project number in the PROJECT table. Unless that project number already exists in PROJECT, it cannot be inserted into the employee–project relation — that restriction is an insert anomaly waiting to happen whenever we try to record a work assignment before the project itself exists. Now suppose a project is closed, completed, or abandoned and we want to delete it from PROJECT. The employee–project rows still point at a project number that no longer exists — a dangling reference, called a zombie in the discussion. Deleting the parent would orphan the children.

Worked example — the zombie project

A concrete version came from the course itself: students registered in this course are also registered in a university program. If a student withdraws from the university program, that student's name disappears from the program's database — so the same name should no longer exist in the course's database either. When we want to delete such an entry, one of three things can happen:

  1. Cascade delete — everything related to the entry is deleted too. If the student withdraws from the program, all records that mention the student are deleted everywhere.
  2. Prevent the deletion — we refuse: you cannot withdraw; at most you take a break for a semester or two.
  3. Insert a default value — the referencing attribute gets a dummy or default value instead of the deleted key.

Which policy you pick is the database designer's or administrator's decision, and it depends on the constraints and the relation in question. It is a policy decision, not a mechanical rule.

The same three options answer the practical question a student raised from personal experience: when updating, which table do we update first — the primary key side or the foreign key side?

Q: In practice, even without redundancy, when two tables are linked by primary key and foreign key, which table do I update first? I have seen the system simply refuse the change while there is a time gap between the two updates.

A: Either of three things can happen, and which one happens is your choice as the designer or administrator depending on your constraints: use cascade delete (or cascade update), put in a default value, or refuse the change. The same options apply to insert and delete restrictions from foreign keys — this is a policy decision you make for your relation.

4.1.4 Guideline 3: Least Null Values

The third guideline: the relation should contain as few null values as possible. A null is a missing value, and missing values are a symptom of a bad fit between the schema and the reality it models.

The phone-number discussion in the first normal form section (see 4.4.2) shows why: if we solve a multi-valued attribute by creating phone1, phone2, phone3 columns, most rows carry nulls. A student with one phone number fills only phone1; the other two cells sit empty. And nulls are not passive — they make queries and decisions awkward:

  • A query counting phone numbers must remember to exclude nulls, or the count is wrong.
  • A query joining on a column that is often null silently drops rows.
  • A human reading the table cannot tell whether phone2 = NULL means "no second number" or "second number not yet recorded."

Least nulls is a design goal in its own right, not just a side effect of good design.

4.1.5 Guideline 4: Least Spurious Tuples

The fourth guideline: the design should create as few spurious tuples as possible. Spurious means extra or wrong — a student suggested "duplicate," which the discussion accepted as the everyday sense. Spurious tuples appear when we join two tables and the join produces rows that were not really there. Extra rows look harmless — more is more — but the problem is the reverse: when extra entries appear, we cannot take a decision on the result, because we do not know which rows are real and which are artifacts of the join.

Why do spurious tuples appear? A join that matches on a non-primary-key or non-candidate-key attribute can multiply rows, because the join key is not guaranteed unique on the "one" side.

Worked example — joining on the wrong column

Take the employee–project relation but drop the project number, leaving employee number, employee name, project name, and hours. Four employees work on three projects:

  • Employee 1 and employee 2 both work on a computational project.
  • Employee 3 works on an electrical project.
  • Employee 4 works on an electronics project.

If we join on project name alone, the two computational-project employees both match the same project row, and every projection of that join can fabricate combinations that never existed — rows that claim employee 1 worked on employee 2's project and vice versa.

Now restore the project number as the join key. Employee 1's rows and employee 2's rows remain distinct, because the key tells us exactly which (employee, project) pairs are real. The moral: joins over non-key attributes produce more (spurious) tuples, and that is a hallmark of a bad design. We will examine the mechanism in detail later in the course — it is exactly what a lossless join property protects against.

Pitfalls

  1. Treating spurious tuples as harmless. Extra rows are not free information; they corrupt every count, average, and decision made on the join result.
  2. Joining on names instead of keys. Two projects can share a name and two employees can share a name; names are for humans, keys are for joining.
  3. Forgetting that this is one of the four guidelines. Removing redundancy helps, but a schema that still joins badly is not a good schema.

A second, denser example of the same four guidelines: a schema holding employee department, employee name, social security number, birth date, address, department number, department manager SSN, and a project relation holding project SSN, P number, hours, E name, P name, and location. Here the department number and the department manager are redundant: if the department name changes from Research to R&D (or whatever new name we choose), the change must be propagated everywhere the name appears, and the employee name stored in the project relation repeats across every project row too. Four things, then, to minimize in a good design: semantic confusion, redundancy and update anomalies, nulls, and spurious tuples.

4.1.6 Worked Example: The Marketplace Sales Design

Worked example — modeling a sale on a marketplace

A marketplace application — think of Amazon as the example — has people who list products and people who purchase them. We have a SELLER entity, a BUYER entity, and a PRODUCT entity. The design question: when a sale happens, how do we model it?

Option A: make SALES a relationship among three entities — a ternary relationship between buyer, seller, and product.

Option B: make SALES a separate entity, then connect it with binary relationships: a relationship between buyer and sales, a relationship between seller and sales, and a relationship between product and sales.

Which one is better? The choice was deliberately left open to the designer — both are legal, both can be argued — but the point was made that the choice matters enormously once the model is converted into a schema and used daily. Think about what each option forces downstream:

  • Option A encodes "this buyer bought this product from this seller" as one triple; changing any one leg of the deal is a change to the single relationship row.
  • Option B lets each sale carry its own attributes (quantity, price, date) naturally, because it is an entity; the binary links then say who bought, who sold, and what.

A designer who cannot defend the choice, and a schema whose quality cannot be judged, is exactly the situation normalization is meant to fix. The exercise is a live demonstration that requirement specification, ER modeling, and relational conversion leave ambiguity in the process, and that ambiguity is the gap the four guidelines close.

4.1.7 What the Guidelines Are For

Two threads close this section. First, redundancy alone is not the only enemy; the guidelines exist so the design can be justified with mathematical certainty rather than left to the guts, whims, and feelings of the designer. Second — and this is the link to the whole lecture — the four guidelines are exactly what normalization will provide, and functional dependencies are the tool that will let normalization provide them.

Recap + bridge: A good relation is one that stores facts once (clear semantics), keeps redundancy and update anomalies minimal, keeps nulls minimal, and never fabricates rows on join. The rest of this lecture is the machinery for achieving those four goals: functional dependencies give us a formal language for the semantics of the data (4.3), and the normal forms use that language step by step (4.4). Next we answer a question that must be settled before the machinery matters: do these rules apply when the database is not relational at all — NoSQL, spreadsheets, and databases already running in production?

4.2 When the Guidelines Apply: NoSQL, Performance, and Change

4.2.1 Different Priorities for Different Eras

Hook: Is a schema that deliberately stores the same fact three times a bad schema? At Facebook's scale, sometimes it is the only schema that works. The four guidelines are not laws of nature — they are the right priorities for one era of computing.

A student asked whether these four guidelines are relational-only — she had heard that NoSQL stores things as JSON files. The answer is a history lesson that explains why the rules exist at all.

When the relational model became famous, in the 1960s, 1970s, and early 1980s, the dominant concern was consistency: the database must give the correct answer, and the entire model was built around that. Around 2003–2005, a flood of new data arrived and social media applications appeared. Now the designer had to choose where to spend limited effort: consistency, isolation (availability), or partition tolerance. Which do we value more — consistency or availability? For a social media application the size of Facebook, an insistence on strict relational consistency means the application will not scale. Scaling needs places where entries are null, places where some redundancy is deliberately kept — the same fact stored at three different sites so that even if one site goes down, the others still serve it.

So the two eras have different priorities. Relational priorities fit enterprise-level applications that do not serve a billion users. NoSQL priorities are scalability and performance, and the JSON file format serves them: it gives freedom to store whatever is needed as the need arises; it puts a lot of related data in the same place, which is a performance advantage; it supports replication and sharding; and it can be stored very tightly to the hardware through proprietary file formats — MongoDB, for example, stores documents in BSON (binary JSON), a compact binary encoding of JSON that makes retrieval very fast. Yes — JSON entries sometimes violate relational ideals such as these four guidelines, but they do so because the priorities are different, not because the designers are careless.

Q: Is this concept valid only for relational databases? I have heard that NoSQL uses JSON files instead.

A: Yes, these guidelines are relational in spirit, and you should understand why they exist. The relational model's major constraint was consistency — giving the correct answer — and it dominated from the 1960s to the early 1980s. Around 2003–2005, social media created new demands, and designers had to choose between consistency, availability, and partition tolerance. Facebook could not scale under strict relational consistency; it needs nulls and deliberate redundancy stored in several places so it stays available. JSON files give freedom, performance by keeping data together, replication, sharding, and very fast retrieval — at the cost of relaxing relational ideals. Different era, different priorities.

Exam note: The four guidelines are not universal laws; they are the relational model's answer to a specific priority — consistency. When a system's priority shifts to availability and scale (the social-media era, 2003–2005 onward), deliberate redundancy and nulls become acceptable. An exam question on "why does NoSQL violate the normalization ideals?" is answered by this trade-off, not by careless design.

4.2.2 Changing a Database That Is Already in Production

Another student asked the course-correction question: suppose a database was built early in the design phase without awareness of good practices like normalization, and only later, in production, do we realize improvements are needed. Can we take a course correction, and what does it do to data integrity?

The answer: yes, we can move from a lower normal form to a higher one (say, from first normal form to third normal form) — every action has a cost, and three things decide the price. First, how strong and how large the existing database and its instances are. Second, how quickly and how often new data arrives — the normalization practices exist for a purpose, and if large amounts of new data keep coming, there is a constraint to enforce. Third, the agenda: why do we want to change, is the current design actually causing problems, and is it stopping us from reaching the next level? On integrity: yes, you stop for some time, redistribute the entire data into the new tables that satisfy the higher normalization levels. The migration is a planned stop-and-redistribute operation, not a live hot-swap.

Q: If the database was built in the early design phase without knowing good practices, and we discover in production that normalization improvements are needed, can we take a course correction? What happens to data integrity?

A: Yes. The cost depends on three things: how strong and how big the existing instances are; how quickly and how often new data arrives; and why you want to change — is the current design causing a problem and blocking your next level? On integrity: you stop for some time, then redistribute the entire data into new tables that satisfy the higher normalization levels.

Pitfalls

  1. Treating migration as a hot-swap. A live "swap the tables while users keep working" is not how normalization changes happen; the class answer is a planned stop, redistribute, and resume — and that planned downtime is part of the cost you must budget.
  2. Normalizing in production on impulse. Before migrating, answer the three cost questions; if the current design is not actually blocking anything, the migration may cost more than it saves.

4.2.3 Principles Apply Even When the Tool Is Different

A student working without a relational database — keeping data manually in an Excel sheet or any tabular form — asked how these guidelines can apply to that. The answer was about principles versus applications. When we learn something, there are two things: the theorem and the application of the theorem. This course teaches the applications first and then asks whether the theorem makes sense. If you know the theorem, you can decide cautiously that a particular rule does not apply to your case and consciously use only one or two rules with different tools — NoSQL instead of ER models and relational schemas. If you do not know the theorem, some of your dates will work and some will not, and you will not know why. The rule is: know why you are doing what you are doing, then violate consciously.

Q: If I build data without a relational database — say, manually in an Excel sheet — can these guidelines apply at all?

A: In principle, yes, and you need the principle to decide when to use it. Learning anything has two parts: the theorem and its application. If you know the theorem, you can consciously decide "this rule does not apply to my case" and pick the tools that fit — including NoSQL instead of relational schemas. If you do not know the theorem, you cannot tell which parts of what you are doing are safe. Know why, then deviate deliberately.

4.2.4 Mixing SQL and NoSQL

A student reported that in one of her projects the team used a combination of Mongo and MariaDB — one NoSQL and one SQL — and asked how that works. First, what NoSQL really is. It is not "the opposite of SQL" as a resume keyword. NoSQL is a family of systems with major categories: key-value stores like Cassandra, document stores like MongoDB, graph databases like Neo4j, and others. Each category has a specific provision: some allow more consistency, some more availability, some more partition tolerance — each exists for its own reason. When storing data, the database must be homogeneous: either we store everything in relational tables or we store everything in the same non-relational format. Two different ways of storing the same thing make it very difficult for the systems to survive simultaneously and add value.

The practical answer for the Mongo-plus-MariaDB case: in application design today we have microservices, and different parts can be programmed in different languages and exposed through different APIs. It is quite likely that the two stores are exposed through separate APIs, each service talking to its own database. The student confirmed the pattern: they process heavy reports through the SQL store and then transfer the result into the NoSQL store to manipulate it. The closing comment: things happen in practice in ways textbooks would not agree with, and as an entrepreneur or decision-maker you take decisions for the application. In commercial applications we have seen rules purposefully violated for scaling: skip the proper requirements initially, make money quickly, then later take a cautious decision to stop, worry about security and other aspects, and migrate.

Q: Can we combine SQL and NoSQL databases in one design, based on the requirement? In one of my sections they use Mongo and MariaDB together.

A: First, NoSQL is not a single thing — it is families: key-value stores like Cassandra, document stores like MongoDB, graph stores like Neo4j, and more, each with its own consistency, availability, or partition-tolerance trade-off. Your database needs to be homogeneous inside one store. The Mongo-plus-MariaDB pattern you saw is probably two microservices exposed through different APIs — the SQL store handles heavy reports, then the result is pushed into the NoSQL store for manipulation. Textbooks will not agree with such setups, but as a decision-maker you weigh the value addition. Commercial applications do purposefully violate rules to scale fast, then migrate later with a cautious stop-and-migrate plan.

4.2.5 What Language Is Used to Talk to a Database?

A student from a non-programming background asked what kind of coding makes a database different from plain Java or C — why can we just query and get results without worrying about indexing and such? The answer: the language used to store and retrieve data is SQL. Application languages — Python, Java, and many others — support SQL integration in one way or another. The whole application may be written in Python, but wherever the application needs data, it uses SQL to query the stored sources and retrieve the data. SQL is the query language of this course and of the relational world.

Q: What kind of coding makes a database different from plain Java or C — why can we just query and get results?

A: The language used to store and retrieve data is SQL. Application languages — Python, Java, and many others — support SQL integration in one way or another. The whole application may be written in Python, but wherever the application needs data, it uses SQL to query the stored sources and retrieve the data.

4.2.6 Does Normalization Always Give Good Performance?

A student asked directly: does normalization always give good performance? The answer was an emphatic no — you have to give something to get something. Normalization means dividing tables, and if your workload is heavy on retrieval, the joins you must perform can cost more than the redundancy they remove. This is exactly why JSON files can be faster: everything needed is combined in the same place, which normalization forbids — normalization says split into different tables. If your client frequently asks for large amounts of data and you spend significant time joining tables, normalized design can leave you with worse performance. The follow-up question — when do we stop normalizing? — has no formula. It is your decision as a designer, and you can reverse it: today you normalize for cleaner and faster storage; in a month, if a few clients suffer, you can denormalize. The decision balances performance, efficiency, and the load and volume of the organization.

Q: Does normalization always give good performance?

A: No. You give something to get something. Normalization divides tables, so every query that needs data from several tables pays join costs. If your retrieval load is heavy, joins can hurt more than redundancy did — this is why JSON files are often faster: related data sits together, which normalization forbids. It is your decision, based on performance, efficiency, load, and volume — and you can denormalize later if the clients suffer.

Pitfall — the normalized-query trap. Many developers assume a "clean" schema is automatically a fast schema. A normalized design is clean for updates; it can be slow for heavy read workloads because each read must stitch tables back together with joins. The decision to normalize or denormalize is workload-dependent: update-heavy stores want normalization, read-heavy analytics often want denormalization (or a JSON store).

Recap + bridge: The four guidelines apply where consistency is the priority. NoSQL, spreadsheets, and production databases each change the equation — and knowing the theory is what lets you deviate deliberately. The next section builds the formal tool that makes the guidelines precise: functional dependencies, the language in which "this design is provably better" can actually be written down.

4.3 Functional Dependencies

4.3.1 Dependency and Function in the Real World

Hook: If employee number 101 appears three times in a table, must employee name Ravi appear all three times too? A functional dependency is the tiny rule that answers questions like this with mathematical certainty — and it is the same idea as the "dependency" between an earning member of a family and their dependents.

Functional dependencies are the tool that will deliver all four guidelines: clear semantics, least redundancy and update anomalies, least nulls, and least spurious tuples. They are in the textbook and they earn marks, but the real reason to learn them is that they power your career decisions later. To understand functional dependency, take the two words separately.

Dependency exists in the real world. In the insurance world, there is an earning member and other dependent members of the family. In an organization, one team's work depends on another team's code: if there are four verticals or four horizontal pieces, success or failure propagates along the dependencies between them. A functional dependency is the database version of exactly this idea.

Function, too, is an everyday idea. A function is a black box: you put an input in, and an output comes out.

Worked example — the square function as a black box

Take , where names the function, is the input, and (x times itself) is the output.

  • Input 2 → output 4 (because ).
  • Input 4 → output 16 (because ).
  • Input 3 → output 9 (because ).

The pattern is certain and modeled: the function states exactly the relationship between one set and another. Where there is a function, there is no guessing. If you know the input, you know the output — always, for every row that uses the same input.

4.3.2 The Formal Definition of a Functional Dependency

In the database world, a functional dependency (FD) says: if there is an attribute in a table and an attribute in the same table, and functionally determines , written

then whenever repeats in the table, also repeats. Here is called the left-hand side (the determinant) and the right-hand side. One attribute can determine several attributes at once, as in . The left-hand side can also be a group of attributes that repeats together — when the group repeats, the right-hand side repeats with it.

Formalize — what really means

For attributes and of one relation:

  • Read it as: " determines ", " is functionally dependent on ".
  • The rule: any two tuples that agree on must also agree on .
  • Left-hand side (LHS): , the determinant — the attribute (or attribute group) that does the determining.
  • Right-hand side (RHS): , what gets determined — one or more attributes.
  • Group determinants: the LHS may be a set such as ; when the whole set repeats, the RHS repeats with it.

Think of a key-value lookup: is the key, is the value. Same key → same value, always.

The definition is one-directional, and that direction is the heart of it. Suppose department number functionally determines department name:

Whenever department number 5 appears, the department name is always Research. But the reverse is not certain: Research may repeat even though the department number is 7 — two departments can share a name. So does not imply . It is a one-way dependency.

Intuition — why it is one-way. The direction is exactly the direction of the function. In , knowing pins down — but knowing does not pin down , because could be 4 or . The FD is the same: the number identifies the name; the name does not identify the number. "Number 5 is always Research" and "Research is always 5" are different claims, and only the first one is guaranteed.

What does an FD tell us? It tells semantics: the attributes of a relation are not independent islands; they are related. If employee number repeats, employee name repeats; if employee email ID repeats, employee name repeats. These statements are the semantics of the mini world, made explicit. That is the purpose for the existence of functional dependencies — and how they actually reduce redundancy and update anomalies appears in the normalization section.

4.3.3 Reading Functional Dependencies from a Schema

When we look at an instance of a relation, we can check whether a candidate FD holds. In an example relation, we asked: is there an FD from to , i.e., whenever repeats, does repeat? No. From to ? No. Any other FD in this relation? None visible. Whether an FD exists or not, we cannot always say with certainty from one instance — more on that in 4.3.5.

In a previous example we could decide: is there an FD from department number to department name? Yes — whenever the department number repeats, the name repeats too. From project number to project name? It looks that way. Note the trap: two project names can be equal — project 5 is Research and project 7 is also Research. That does not break (a number always maps to one name); it only shows the reverse direction fails, because Research does not always map to one number. The FD means "number 5 is always Research", not "Research is always 5".

Worked example — reading FDs from a small instance

D number D name
5 Research
7 Research
9 Sales

Check : does any D number repeat with two different names? No — 5 always gives Research, 7 always gives Research, 9 always gives Sales. The FD holds.

Check the reverse, : does any D name repeat with two different numbers? Yes — Research appears with 5 and with 7. The reverse FD fails.

Sense-check: the number maps to one name, but the name maps to many numbers. This is the one-way nature of functional dependencies, and it is exactly why a name is never a safe join key.

4.3.4 Who Decides What the Functional Dependencies Are

A student building a school database — student ID, student name, father's name, mother's name — asked how we decide the functional dependencies there. The answer is the most practical statement of the section: functional dependencies are not decided by the relational schema, and they are not derived from the ER diagram. They exist — that is all. The person who knows them is the person who gave you the constraints: the user, the client, the person who gave the assignment to develop the database. Given only the final relational schema, nobody can say which FDs exist or do not exist; the designer knows them from the user's requirements.

Q: For a school database with student ID, name, father's name, and mother's name, how do we decide the functional dependencies?

A: You do not decide them from the schema — they exist, and the person who knows them is the client who gave you the constraints. Given only the final relational schema, no one can say which FDs exist. The user tells you, and the database administrator writes the FD set down. It is the same source as every other constraint: the requirements.

How are they recorded? Functional dependencies form a separate set, written down separately. The relational schema shows candidate keys and the primary key (underlined), and foreign keys from an attribute of one relation to the primary key of another. Functional dependencies are not represented in the relational schema, and the ER diagram cannot produce them. The customer provides the inputs, and the database administrator writes the set down. That set then drives normalization, reduces redundancy, and ensures joins do not create extra or missing entries. FDs also have a second job: when we are given a relation without a primary key, the functional dependencies are used to identify the candidate keys and pick the primary key.

Q: How do we capture functional dependencies in the ER diagram, alongside primary keys and foreign keys?

A: We do not — they are a separate set, written separately. The relational schema shows the primary key (underlined) and foreign keys; the FD set lives outside both the schema and the ER diagram. The customer provides the inputs and the administrator notes them down. The set is then used for normalization, for reducing redundancy, for ensuring proper joins, and sometimes to identify the primary key and candidate keys when a relation is given without one.

One student summarized an FD as a hard-and-fast business rule that may oblige us to create a composite primary key. The response accepted the direction — "you are correct" — while noting that the composite-primary-key mechanics come later: these things are controlled by the business, meaning user requirements and how the business grows. Constraints, limitations, and regulations from the user help us understand the relational schema better, make normalization better, and ultimately make application performance better.

Q: Can I summarize an FD as a hard-and-fast business rule that obliges us to create a composite primary key?

A: Correct in direction — these things are controlled by the business: user requirements and how the business grows. Composite primary keys are a mechanics point for later. Constraints and limitations from the user help us understand the schema better, make normalization better, and ultimately improve application performance.

Pitfall — inventing FDs from the table. The biggest beginner trap is to look at a relation instance and "discover" FDs in it. FDs are facts about the mini world, given by the client — an instance can show you that an FD fails, but it can never prove that one holds. The FD set is an input to the design, not an output of staring at the schema.

4.3.5 What a Relation Instance Can and Cannot Prove

A student asked for an example of a subtle claim: we can definitely conclude that certain FDs do not exist — because two tuples in the instance violate them — but we can never conclude that an FD does exist.

Worked example — refuting an FD with one counterexample

Consider an instance with two attributes, teacher and course:

teacher course
Smith Databases
Smith Networks
Lee Databases

Check : does every teacher map to exactly one course? Smith maps to Databases and Networks — two rows with the same teacher and different courses. That single pair of rows breaks permanently; no future data can repair it, because the definition "same must imply same " is violated.

Now check : Databases appears twice, and both times the teacher is Smith. It looks fine — but we can only say it may exist. A future row where Networks is taught by a different teacher, or where a new course maps to a different teacher, could still refute it. The instance shows no violation today, but it proves nothing about tomorrow.

On the other hand, for any FD that seems to hold in the instance — say from text to teacher — we can only say it may exist. In short: one counter-example refutes an FD forever; supporting examples never prove one. This is why the FD set comes from the client, not from inspecting instances.

Q: Give me an example for the claim that we can definitely conclude certain FDs do not exist, because two tuples violate them.

A: Take the instance at hand: we can say for sure that there is no FD from teacher to course — the teacher repeats while the course does not. But for a dependency that happens to hold in the instance, like text to teacher, we can only say it may exist; a future entry where the same text maps to a different teacher would refute it. Instances can disprove FDs, never prove them.

Q: Can we conclude that the whole objective of normalization is to ensure that even when an FD exists, we never repeat the same record or the same two or three attributes in the same table?

A: Yes — removing redundancy and its update anomalies is one purpose, and it is what was confirmed as "the entire exercise." But it is only one of the four guidelines: we also want clear semantics, the least nulls, and the least spurious tuples. All four are satisfied through functional dependencies.

4.3.6 Why Functional Dependencies Matter

Collect the thread: a good schema has clear semantics, least redundancy and update anomalies, least nulls, and least spurious tuples. To guarantee all four with mathematical certainty, we use functional dependencies: they encode the semantics of the mini world, they drive the decomposition that removes redundancy, and they keep joins clean. The rest of the session — first normal form, second normal form, third normal form, BCNF — is the step-by-step use of FDs to reach a good relation.

Recap + bridge: A functional dependency says: same , same — always, one-way, and it is a fact given by the client, never one we can prove from an instance. FDs are the grammar the normal forms will speak. Next, the normal forms themselves: first, the rule that one cell holds one value; then the rules that use FDs to break a bad relation into good ones.

4.4 The Normalization Process: 1NF, 2NF, 3NF, BCNF

4.4.1 What Normalization Is

Hook: Normalization is the only "recipe" in this course that turns a relation you cannot defend into relations you can — one rule at a time, in a fixed order, with the functional dependencies as the ingredients.

Normalization is the process that removes bad, unsatisfactory relations and converts them into good relations. We have seen what a good relation is — clear semantics, least update anomalies, least null entries, least spurious tuples. Anything that does not satisfy those is a bad relation, and normalization breaks bad relations into good ones.

Purpose — what normalization is for. The input to normalization is a 1NF relation that carries redundancy and update anomalies; the output is a set of smaller relations in which each non-key fact is stored once. The process is staged: first we satisfy first normal form; then, on top of that, second normal form; then third normal form, and beyond that the stricter BCNF. Each stage adds a condition, so by default, third normal form already respects the restrictions of second normal form — the forms stack like layers of a filter, not like alternatives.

The steps in order:

  1. 1NF — one value per cell.
  2. 2NF — every non-key fact must depend on the whole key, not just part of it.
  3. 3NF — every non-key fact must depend on a key directly, not through another fact.
  4. BCNF — even stricter than 3NF; covered in later sessions.

Each step starts from the relation produced by the previous step, and each step uses the functional dependencies given by the client as the ground truth.

4.4.2 First Normal Form (1NF)

First normal form (1NF) says: every record, and every cell in every record, holds a single distinct entry. One value per cell. That sounds trivial, but it is not, and the lecture spent real time on why it exists.

Take a relation storing student name, student ID number, and student phone number. A normal person can have two phone numbers — one mobile and one office — and some people have three: office, home, and a personal contact. Today you might have two; 15 or 20 years ago you had one; within the next 5 to 10 years you might have three or four. Any design that hard-codes a maximum ("no more than three") is planning to fail over a 10-to-20-year application lifetime.

Worked example — three ways to store several phone numbers

Suppose student Riya (ID 2024001) has the numbers 9999999999 (mobile) and 01234 01596 (office). Three storage designs were discussed in class:

  1. One cell, several values: store all numbers together, separated by commas — 9999999999, 01234 01596, .... One row, one cell, three values inside it.
  2. Fixed columns: create phone1, phone2, phone3 attributes. Riya fills phone1 and phone2; phone3 is null. A student with one number fills only phone1, leaving two nulls.
  3. Repeated records (or a separate table): store one (student, phone number) pair per record — Riya's name appears twice, once per number, in two different rows. This was a student's suggestion, and the discussion pointed to it as "the process of normalization": we will see that the separate table is the answer.

Which option is better, and why does 1NF forbid the first? The answer lives in the storage layer, and the story went through the old hard disk model: data lived on disks with tracks and a spindle; the head had to move to a particular track and a particular sector to find a record. To know where a record starts and ends, the system had to know how much space each value occupies. If one cell can hold one number or three numbers, the size of the cell is unpredictable, and the system cannot predict where the data resides. Searching compounds the problem: the search algorithm must not only find the attribute, but also search inside the attribute — splitting on comma or semicolon or space — to decide whether a match exists. Every query that asks "which students have three phone numbers?" or "who has this specific number?" must scan inside every cell of every row. The algorithm becomes more complex and slower, and the semantics become unclear: is this one value or many? Option 2 was deferred as bad too — it fills the table with nulls (guideline 3) — but at minimum, 1NF demands a single entry per cell.

Sense-check: with option 3 the table holds exactly one fact per row, every cell has a predictable size, and a search for a number scans whole cells, not fragments inside them.

Q: Of the three ways to store multiple phone numbers — one cell with commas, three fixed columns, or repeated records — what is wrong with the single cell?

A: Storage and search. On disk, records live at predictable locations — track and sector — and a cell of unpredictable size breaks that prediction. Queries also become complex: to find students with a given number, the algorithm must search inside the attribute, splitting on commas, semicolons, or spaces. Option two fills the table with nulls; option three (separate records or a separate table) is what normalization produces.

A student summarized it: 1NF solves the problem of storing only a single value of an attribute in a column, not multiple values. The summary was confirmed and extended with the reasons: cleaner design, efficiency, and clear semantics — the unclear semantics of multi-value cells are precisely what produces bad performance.

Q: Is it correct that first normal form solves storing only a single value of an attribute per column, not multiple values?

A: Yes, that is exactly what 1NF is. It solves the problem of cleaner database design, of efficiency, and of clear semantics — multi-value cells produce unclear semantics, which ultimately result in bad performance.

Pitfalls

  1. Hard-coding a column count for a multi-valued fact (phone1–phone3). It passes 1NF but breaks guideline 3 by filling the table with nulls — and it breaks the moment someone needs a fourth number.
  2. Assuming "one value per cell" is easy to verify. The rule is about distinct entries: 9999999999, 01234 01596 is still two entries in one cell even though it is one string.

4.4.3 Second Normal Form (2NF)

Second normal form (2NF) demands full functional dependency: for every functional dependency , the left-hand side must be a complete candidate key — not just part of one.

To parse that, recall the key terminology from the earlier session. A super key is a set of attributes that uniquely identifies every record. A minimal such set is a key. When there is more than one minimal set, each one is a candidate key. One candidate key is chosen as the primary key. An attribute that belongs to some candidate key is a prime attribute; an attribute that belongs to no candidate key is a non-prime attribute.

Formalize — the 2NF condition

For a relation in 2NF, every functional dependency

must satisfy: is a complete candidate key and is a non-prime attribute. In words: no non-prime attribute may depend on only a part of a candidate key.

  • If the left-hand side is a part of a candidate key, the dependency is a partial dependency, and 2NF is violated — provided is non-prime.
  • If the candidate key has three attributes, no subset of one or two of them may determine any non-prime attribute.
  • If is a prime attribute, there is no violation at all.

The 2NF violation test for a dependency : left side is a proper part of a candidate key AND right side is a non-prime attribute → violates 2NF.

4.4.4 Worked Example: Splitting the Employee–Project Relation

Worked example — 2NF in action

The employee–project relation has attributes SSN, P number, E name, P name, P location, and Hours. SSN and P number together form the candidate key — the pair uniquely determines everything else, so the pair never repeats. Now examine the functional dependencies:

  1. — holds by virtue of the key.
  2. — whenever SSN repeats, E name repeats.
  3. — whenever P number repeats, the project name and location repeat.

FDs 2 and 3 both violate 2NF. In FD 2, the left-hand side SSN is a part of the candidate key — not the complete key — and E name is non-prime. In FD 3, P number is a part of the candidate key, and P name and P location are non-prime.

The fix is to decompose on the violating dependency. For FD 2, create a separate relation . For FD 3, create a separate relation . The original relation keeps the complete candidate key and everything not moved out: SSN, P number, and Hours. After both splits we have three relations:

Each new relation is in 2NF because every non-prime attribute now depends on the complete key of its own relation. Consider a concrete instance: SSN 123-45-6789 works on project P1 for 20 hours, and the project P1 is Billing in Wing A. Before the split, the project's name and location sat in every employee row for the project; after the split, (P1, Billing, Wing A) lives once in the project relation, and the works-on relation stores only (123-45-6789, P1, 20).

Sense-check: renaming Billing now touches one row instead of one row per employee — the update anomaly from section 4.1 is gone, and the join on P number reconstructs the full picture without losing any fact.

4.4.5 Third Normal Form (3NF)

Third normal form (3NF) forbids transitive dependencies: no non-prime attribute may determine a non-prime attribute. Formally, for every functional dependency , at least one of these must hold: is a candidate key or a super key, or is a prime attribute. The violation case is: is not a candidate/super key AND is not a prime attribute.

Because 3NF is built on top of 2NF, it already inherits the ban on partial dependencies; 3NF adds the ban on non-prime-to-non-prime dependencies. BCNF, mentioned as even stricter, comes after 3NF and will be revisited in later sessions.

The chain of dependencies 3NF removes

A transitive dependency is a chain through a middleman. If and , then follows by transitivity — and if and are non-prime and is not a key, then the fact about travels through , and changing forces changes in that were never needed. 3NF's job is to break the chain: each non-prime fact should depend on a key directly, not through another non-prime attribute. (In the reference textbook: a 3NF relation's FD diagram has arrows out of candidate keys only — any extra arrow out of a non-key attribute marks a transitive dependency.)

4.4.6 Worked Example: Splitting the Employee–Department Relation

Worked example — 3NF in action

Start from the employee relation whose candidate key is SSN alone: SSN, birth date, address, D number, D name, D manager. The functional dependency

is a transitive dependency. D number is not a candidate key or super key, and D name and D manager are non-prime attributes — so this FD violates 3NF. (Notice this is not a 2NF violation: SSN is the whole key, so nothing is partial.)

The fix: create a separate relation containing the left-hand side and the right-hand side together, . The original relation keeps its key plus everything else: SSN, birth date, address, and D number — the left-hand side attribute stays in the original relation, because it still links the two tables. After the split:

Concretely: employee 123-45-6789 works in department 5 (Research, manager M100). Before the split, the pair (Research, M100) was repeated in every employee row of department 5; after the split, it lives once in the department relation, and the employee relation keeps only (123-45-6789, ..., 5). When the manager of Research changes from M100 to M200, exactly one row changes.

The rule to remember for decomposition: keep the left-hand side attribute in the original relation, and carry it together with the right-hand side into the new relation.

Sense-check: every fact still exists after the split (the join on D number rebuilds the old table), but each fact now lives in exactly one place.

4.4.7 Class Exercise: Prime Attributes and 3NF Violations

The class worked a property-schema exercise designed to trap people who memorize the rule without the terminology.

The relation has attributes property ID, country name, lot number, tax rate, area, and price. Property ID is a prime attribute and functionally determines everything — it is a candidate key. There is a second candidate key: country name together with lot number. So there are two candidate keys:

  • property ID
  • (country name, lot number)

All three of these attributes are prime attributes (each belongs to some candidate key). Here is the trap: when either side of a dependency involves prime attributes, the dependency may still violate nothing. Any dependency whose right-hand side is a prime attribute can never violate 2NF or 3NF, because the 3NF rule is satisfied as soon as is prime.

Q: I am confused about what a prime attribute is. Is it part of the primary key, or a composite key that uniquely identifies a record?

A: Start from the top. A super key is a set of attributes that uniquely identifies every record. A minimal super key is a key. When several minimal keys exist, each is a candidate key, and you choose one as the primary key. A prime attribute is any attribute that is part of a candidate key. In this schema, property ID is one candidate key and (country name, lot number) is another, so all three attributes are prime.

Question 1: does the FD violate 3NF? The class split. One student answered that it violates, because a non-prime attribute is identifying a non-prime attribute. But that reasoning was wrong for this FD: tax rate is indeed non-prime (it belongs to no candidate key), but country name is prime (it is part of the second candidate key). The right-hand side is prime, so the dependency satisfies 3NF: does not violate third normal form.

Q: Does the functional dependency tax rate to country name violate third normal form?

A: No. Check the two conditions: on the left, tax rate is a non-prime attribute (it belongs to no candidate key); on the right, country name is a prime attribute, because country name together with lot number forms the second candidate key. Since the right-hand side is prime, the dependency satisfies 3NF — a non-prime attribute is not determining a non-prime attribute here.

Question 2: does the FD violate 3NF? This time, yes. Area is on the left and is not a complete candidate key (it is not a candidate key at all), and price is not a prime attribute. Left side not a candidate/super key, right side not prime — violation. The fix follows the rule: create a separate relation , and keep all attributes except price in the original relation.

Q: Then what about area to price?

A: That one violates 3NF. Area is on the left and is not a complete candidate key, and price is not a prime attribute. Both conditions for violation hold, so we split: create a separate relation (area, price) and keep all the other attributes in the original relation.

Pitfalls

  1. Forgetting there can be more than one candidate key. The (country name, lot number) key is easy to miss, and with it the fact that country name is prime.
  2. Checking only the left-hand side. The 3NF test is two-sided: must be a candidate/super key or must be prime. A non-prime determinant with a prime right-hand side is legal.
  3. Memorizing "no transitive dependencies" without the terminology. The trap in this exercise is exactly that: you cannot apply the rule if you cannot tell a prime from a non-prime attribute.

4.4.8 The Order and the Goal

Normalization proceeds in order: satisfy 1NF, then 2NF, then 3NF. First normal form removes multi-valued cells. Second normal form removes partial dependencies — attributes that depend on part of a candidate key. Third normal form removes transitive dependencies — non-prime attributes that depend on other non-prime attributes. Beyond 3NF sits BCNF, which is stricter, and will appear in later sessions.

One closing caution from the session: a summary line stated the 3NF condition backwards (suggesting that a candidate-key left side or a prime right side violates 3NF). That was a slip of the tongue. The correct statement, given throughout the main discussion, is: a dependency violates 3NF only when is not a candidate/super key and is not a prime attribute. If either condition fails to hold — is a key, or is prime — the dependency satisfies 3NF.

The goal of the whole exercise, restated once more: a good relation has proper semantics, least null entries, least update anomalies and least redundancy, and no spurious tuples. Functional dependencies give us the mathematical certainty to know we have achieved it — instead of relying on the guts, whims, and feelings of the database designer. That is why normalization exists, and why first normal form, functional dependencies, and their inference rules deserve the attention they get.

Assumptions and scope. The normal-form rules assume the functional dependencies are the true semantics of the mini world — if the client's FD set is wrong or incomplete, every verdict drawn from it is wrong. The decompositions also assume lossless joins: splitting on a functional dependency guarantees that joining the pieces returns the original rows and no spurious ones, and this is precisely why the split rule keeps the left-hand side in both relations. The forms are judged against the schema and its FDs, never against a single instance, and no instance can ever prove a relation is in 3NF — it can only fail to disprove it.

Recap + bridge: 1NF makes every cell hold one value; 2NF removes partial dependencies (a non-prime attribute depending on part of a key); 3NF removes transitive dependencies (a non-prime attribute depending on another non-prime attribute); BCNF is the stricter form that follows. Each split keeps the left-hand side in both relations so the join stays lossless. The four guidelines from 4.1 are now supported by provable rules — and the next session moves on to the machinery that decides just how far to push them: the inference rules of functional dependencies.

Key Industry Applications

Normalization and functional dependencies are not textbook exercises; they are daily decisions in the systems described in this lecture.

  • Airline industry: airlines need data about aircraft costs and about demographic, political, and geopolitical events to decide where to redirect planes — a motivating story for why stored, retrievable data matters. Airline reservation systems are also cited as a mini world in their own right: hundreds of agents, concurrent bookings, and one trusted record of every seat.
  • Supply chain companies: must store data properly and ensure it makes sense when retrieved. A part number that maps to two names in two tables is not a style problem — it stops a shipment from being assembled. This is exactly the consistency argument behind least redundancy.
  • Amazon-style marketplaces: the sales-design exercise (ternary relationship vs. separate sales entity with binary relationships) is a live e-commerce schema decision. In production, the sale usually becomes an entity with its own attributes (quantity, price, status), and the binary links to buyer, seller, and product — Option B from the lecture.
  • Social media at scale — Facebook: the history lesson on why NoSQL exists — strict relational consistency does not scale to a billion users, so nulls and deliberate three-way redundancy are accepted for availability. The same fact stored at three sites means one site can fail and the others still answer.
  • NoSQL families in production: Cassandra (key-value), MongoDB (document/JSON, stored in the compact BSON binary format), and Neo4j (graph) — each with its own consistency, availability, and partition-tolerance trade-offs, and each deliberately relaxing relational ideals for scale.
  • SQL-plus-NoSQL hybrid stacks: the Mongo plus MariaDB combination seen in industry, typically two microservices exposed through different APIs — the SQL store handles heavy reporting, the NoSQL store handles manipulation of the results.
  • Microservices and APIs: modern applications split parts into services, sometimes in different languages, each exposing its database through an API — the real-world pattern behind mixed stores, and the reason "which database" is a service-level decision, not a whole-company one.
  • Deliberate denormalization: commercial applications purposefully violate normalization rules to scale quickly, then stop and migrate later — normalization versus performance is an active engineering decision (joins cost time; JSON keeps related data together for fast retrieval). The lecture's answer stands: normalize for updates, denormalize for read-heavy workloads, and decide with the theory in hand.
  • National ID systems: the SSN discussion uses the Aadhaar number as the everyday equivalent of a social security number — a concrete anchor for key attributes, and a reminder that a single national identifier is a candidate key in hundreds of unrelated schemas.
  • Manual data tools: Excel-style manual tabular storage still exists; the principles (not the tools) are what transfer, and knowing the theorem lets you decide when it applies. A spreadsheet with repeated customer names has the same update anomaly as a badly designed table — the fix is the same reasoning, on a smaller stage.
  • Query languages in industry: SQL is the standard way applications written in Python, Java, and other languages store and retrieve data — the query language of this course and of the relational world.

DDA Lecture 4 notes · Normalization: Turning Instinct into Certainty

Database Design and Applications· postgraduate· 2026-08-06

Sections Breakdown

14.1 Why Normalization: Four Guidelines for a Good Relation

The four guidelines for a good relation — clear semantics, least redundancy and update anomalies, least nulls, and least spurious tuples — and why ER design needs measurable criteria.

24.2 When the Guidelines Apply: NoSQL, Performance, and Change

How the guidelines' consistency priority shifts by era: NoSQL trade-offs, normalizing a production database, Excel-style tools, and the performance question.

34.3 Functional Dependencies

The formal tool behind the guidelines: what X to Y means, its one-way nature, and why FDs come from the client, never from an instance.

44.4 The Normalization Process: 1NF, 2NF, 3NF, BCNF

The staged process from 1NF to BCNF: one value per cell, no partial dependencies, no transitive dependencies, with worked decompositions.

5Key Industry Applications

Normalization and functional dependencies as daily decisions in airlines, supply chains, marketplaces, social media, and hybrid SQL-NoSQL stacks.

Postgraduate students of database design and applications

Exam Revision Notes

Below is the distilled, exam-ready core. Every entry comes from the full explanation above. Use this section for rapid review; return to the main notes when a point needs more context.

Why Normalization: Four Guidelines for a Good Relation

Must-know: Four guidelines for a good relation: (1) clear semantics - tables speak for themselves; (2) least redundancy and least update anomalies (update = insert, delete, modify); (3) least null values; (4) least spurious tuples from joins on non-key attributes. An anomaly is a discrepancy breaking a pattern, NOT an outlier.

⚠️ Top pitfall: Associating "anomaly" with an outlier (gifted sports player, ML outlier) instead of a discrepancy or inconsistency that breaks a pattern and blocks insert, update, or delete.

Self-check: Name the four guidelines for a good relation and give one example of each violation.

Connects to: When the Guidelines Apply (4.2); Functional Dependencies (4.3); The Normalization Process (4.4).

When the Guidelines Apply: NoSQL, Performance, and Change

Must-know: Relational priorities (consistency, correct answers) ruled until 2003-2005; then social media made availability and scale dominant, so NoSQL stores (key-value Cassandra, document MongoDB with BSON, graph Neo4j) accept nulls and deliberate redundancy. Normalizing in production means a planned stop, redistribute data into higher-normal-form tables, and resume. Normalization does not always improve performance - joins cost time; denormalization is a reversible designer decision.

⚠️ Top pitfall: Assuming normalization always gives good performance: it splits tables, so read-heavy workloads pay join costs that can exceed the redundancy they remove.

Self-check: Why does a Facebook-scale application deliberately keep the same fact stored at three sites?

Connects to: Why Normalization (4.1); Functional Dependencies (4.3).

Functional Dependencies

Must-know: X -> Y (X functionally determines Y) means: whenever X repeats in the table, Y repeats. It is one-way: X -> Y never implies Y -> X. FDs come from the client's requirements as a separate written set, not from the schema or ER diagram, and they are used for normalization and to find candidate keys. Instances can refute an FD (two tuples with same X, different Y) but never prove one.

⚠️ Top pitfall: Trying to prove an FD exists from a relation instance - a counterexample refutes an FD forever, but supporting examples never prove one; FDs are given by the client.

Self-check: Two departments are both named "Research" with numbers 5 and 7. Which FD holds: D number -> D name or D name -> D number? Why?

Connects to: The Normalization Process (4.4); Why Normalization (4.1).

The Normalization Process: 1NF, 2NF, 3NF, BCNF

Must-know: Normalization order: 1NF (one value per cell), 2NF (no partial dependencies - left side must be a complete candidate key), 3NF (no transitive dependencies - no non-prime attribute determines a non-prime attribute; alpha candidate/super key OR beta prime means no violation), BCNF is stricter and later. Decomposition rule: keep the left-hand side attribute in the original relation and carry it with the right-hand side into the new relation.

⚠️ Top pitfall: The class-exercise trap: forgetting country name is prime because (country name, lot number) is a second candidate key - a non-prime attribute determining a prime attribute does NOT violate 3NF.

Self-check: In the property schema with keys property ID and (country name, lot number), does tax rate -> country name violate 3NF? Does area -> price?

Connects to: Functional Dependencies (4.3); Why Normalization (4.1).

Key Industry Applications

Must-know: The four guidelines are applied with different priorities per era: enterprise relational systems choose consistency, Facebook-scale NoSQL systems choose availability with deliberate redundancy and nulls; denormalization is a reversible, workload-driven decision; the normalization theorem transfers to non-relational tools.

Self-check: Why does a read-heavy analytics store deliberately denormalize data that a transactional system would keep normalized?

Connects to: Why Normalization (4.1); When the Guidelines Apply (4.2).

Was this lecture useful?

Loading comments…
🤖

BitsNotes AI Assistant

Subject Notes Assistant

Configure AI Chat

Choose how to access the chatbot
Have your own API key?

Switch to "Bring Your Own Key" tab above for unlimited access with any OpenAI-compatible provider.

🔑 Enter API key above to fetch live models from provider, or enter model name manually.
OpenAI-Compatible API Support

Choose any provider preset (Gemini, DeepSeek, Kimi, GLM, MiniMax, Qwen, OpenAI, Groq, Ollama, etc.) or enter a custom endpoint URL.

Security & Privacy First

Your API key is sent directly from your browser to your specified provider. BitsNotes servers never store or see your key.