Tutorial

Normalization in SQL: 1NF, 2NF, 3NF & BCNF Explained with Examples

Learn normalization in sql with step-by-step table examples from unnormalized data to 1NF, 2NF, 3NF, and BCNF to eliminate data anomalies.

Anuj SainiSep 8, 20269 min read

In database engineering and business analytics, normalization in SQL provides the structural foundation for relational database design. Without a rigorous normalization strategy, relational databases suffer from bloated storage footprints, duplicate customer details, and dangerous synchronization errors when rows are modified.

In this comprehensive guide, building on what is SQL and DDL commands in SQL, we examine normalization in SQL from the ground up, decomposing a flawed, unnormalized spreadsheet-like table into clean First (1NF), Second (2NF), Third (3NF), and Boyce-Codd (BCNF) normal forms with complete DDL code.


What is Normalization in SQL and Why is It Important?

Relational databases operate on relational algebra and set theory. When tables store repeating groups or dependent attributes across disparate entities in a single row, the database engine suffers from three major anomalies:

  1. Insertion Anomaly: You cannot record information about an entity without creating a dummy record for an unrelated entity (e.g., you cannot add a new course without enrolling a student).
  2. Update Anomaly: Updating a customer's address requires modifying 50 separate order rows. If one update fails or is missed, your database state becomes contradictory.
  3. Deletion Anomaly: Deleting an order accidentally deletes the only existing record of that customer's address or phone number.

Understanding normalization in SQL allows database architects and data engineers to isolate business entities into focused tables, preserving referential integrity and data hygiene.

OLTP vs OLAP Architecture

Transactional systems (OLTP) such as PostgreSQL or MySQL use normalized schemas (typically 3NF) to optimize fast, reliable write operations. Analytical data warehouses (OLAP) often embrace controlled denormalization (Star Schema, Fact-Dimension models) to speed up read-heavy analytical aggregations.


The Progressive Stages of Normalization in SQL

Database normalization follows a sequence of formal rules. Each stage strictly builds upon the requirements of the preceding normal form:

Feature / Criteria

Step-by-Step Practical Example: From Unnormalized to 3NF

To see normalization in SQL in action, consider a messy, unnormalized university enrollment table (StudentCourse_Raw):

StudentIDStudentNameCoursesEnrolledInstructorNameInstructorOfficeCourseFee
101Sarah ConnorSQL, PythonDr. Alan TuringHall B-101500
102John DoeSQLDr. Alan TuringHall B-101300
103Alex MurphyMachine Learning, SQLProf. Ada LovelaceHall A-204900

Stage 1: Achieving First Normal Form (1NF)

Rule: Every cell must contain a single, indivisible (atomic) value. No comma-separated strings or repeated column groups.

To achieve 1NF, we split the multi-valued course lists into individual rows and establish a composite primary key (StudentID, CourseName):

sql
CREATE TABLE student_courses_1nf (
    student_id INT,
    student_name VARCHAR(100),
    course_name VARCHAR(100),
    instructor_name VARCHAR(100),
    instructor_office VARCHAR(50),
    course_fee DECIMAL(10, 2),
    PRIMARY KEY (student_id, course_name)
);
 
INSERT INTO student_courses_1nf VALUES
(101, 'Sarah Connor', 'SQL', 'Dr. Alan Turing', 'Hall B-101', 300.00),
(101, 'Sarah Connor', 'Python', 'Dr. Guido Rossum', 'Hall C-302', 350.00),
(102, 'John Doe', 'SQL', 'Dr. Alan Turing', 'Hall B-101', 300.00),
(103, 'Alex Murphy', 'Machine Learning', 'Prof. Ada Lovelace', 'Hall A-204', 600.00),
(103, 'Alex Murphy', 'SQL', 'Dr. Alan Turing', 'Hall B-101', 300.00);

Problem remaining in 1NF: The table has partial dependencies. student_name depends only on student_id, not on course_name. Meanwhile, instructor_name, instructor_office, and course_fee depend solely on course_name.


Stage 2: Achieving Second Normal Form (2NF)

Rule: Must be in 1NF, and all non-key columns must be fully dependent on the entire primary key. If a table has a composite key, any attribute depending on only half the key must be moved to its own table.

We decompose student_courses_1nf into three dedicated tables:

sql
-- Table 1: Students
CREATE TABLE students_2nf (
    student_id INT PRIMARY KEY,
    student_name VARCHAR(100) NOT NULL
);
 
-- Table 2: Courses
CREATE TABLE courses_2nf (
    course_name VARCHAR(100) PRIMARY KEY,
    instructor_name VARCHAR(100) NOT NULL,
    instructor_office VARCHAR(50) NOT NULL,
    course_fee DECIMAL(10, 2) NOT NULL
);
 
-- Table 3: Junction / Bridge Table
CREATE TABLE enrollments_2nf (
    student_id INT,
    course_name VARCHAR(100),
    PRIMARY KEY (student_id, course_name),
    FOREIGN KEY (student_id) REFERENCES students_2nf(student_id),
    FOREIGN KEY (course_name) REFERENCES courses_2nf(course_name)
);

Problem remaining in 2NF: Notice table courses_2nf. instructor_office depends on instructor_name, which is not a candidate key. This is a transitive dependency (course_name -> instructor_name -> instructor_office). If Dr. Turing moves offices, we have to update multiple course records.


Stage 3: Achieving Third Normal Form (3NF)

Rule: Must be in 2NF, and no non-key attribute can depend transitively on another non-key attribute ($X \rightarrow Y$ and $Y \rightarrow Z$ where neither is a candidate key).

We isolate instructors into their own entity:

sql
-- Table 1: Instructors
CREATE TABLE instructors_3nf (
    instructor_id INT PRIMARY KEY,
    instructor_name VARCHAR(100) NOT NULL,
    instructor_office VARCHAR(50) NOT NULL
);
 
-- Table 2: Courses (Referencing instructor_id)
CREATE TABLE courses_3nf (
    course_id INT PRIMARY KEY,
    course_name VARCHAR(100) NOT NULL,
    course_fee DECIMAL(10, 2) NOT NULL,
    instructor_id INT NOT NULL,
    FOREIGN KEY (instructor_id) REFERENCES instructors_3nf(instructor_id)
);
 
-- Table 3: Students
CREATE TABLE students_3nf (
    student_id INT PRIMARY KEY,
    student_name VARCHAR(100) NOT NULL
);
 
-- Table 4: Enrollments
CREATE TABLE enrollments_3nf (
    student_id INT,
    course_id INT,
    enrollment_date DATE DEFAULT CURRENT_DATE,
    PRIMARY KEY (student_id, course_id),
    FOREIGN KEY (student_id) REFERENCES students_3nf(student_id),
    FOREIGN KEY (course_id) REFERENCES courses_3nf(course_id)
);

Now, all non-key columns depend strictly on the primary key, the whole primary key, and nothing but the primary key. If an instructor changes their office, only a single record in instructors_3nf is modified.


Boyce-Codd Normal Form (BCNF)

Boyce-Codd Normal Form is an advanced extension of 3NF. A table is in BCNF if and only if for every non-trivial functional dependency $X \rightarrow Y$, $X$ is a superkey.

Consider an advisory table where a student can have multiple advisors, but each advisor only works in a single academic department:

sql
-- Flawed 3NF schema with overlapping candidate keys
-- Primary Key: (student_id, subject)
-- Dependency: advisor -> subject (advisor determines subject, but advisor is not a superkey)
CREATE TABLE student_advisors_flawed (
    student_id INT,
    advisor_name VARCHAR(100),
    subject VARCHAR(100),
    PRIMARY KEY (student_id, subject)
);

To bring this schema into strict BCNF, decompose the table into two:

sql
CREATE TABLE advisor_departments (
    advisor_name VARCHAR(100) PRIMARY KEY,
    subject VARCHAR(100) NOT NULL
);
 
CREATE TABLE student_advisors_bcnf (
    student_id INT,
    advisor_name VARCHAR(100),
    PRIMARY KEY (student_id, advisor_name),
    FOREIGN KEY (advisor_name) REFERENCES advisor_departments(advisor_name)
);

Normalization vs Denormalization in SQL

While 3NF is the gold standard for transactional databases, business intelligence and data warehouses often intentionally denormalize schemas:

Feature / Criteria

To write performant queries across normalized production schemas, data analysts combine tables using subqueries in SQL, DDL commands in SQL, and structured Common Table Expressions (CTEs).


Practical Trade-offs: When to Stop Normalizing in Production

In commercial applications, dogmatic adherence to higher normal forms (4NF, 5NF, or even pure 3NF) can introduce unacceptable query complexity and CPU overhead:

  • Reporting Views: Joins across 8 or 10 normalized entity tables to produce a daily executive sales summary consume substantial memory. Database administrators frequently build materialized views or dimensional data marts (Star Schemas) that deliberately duplicate dimension attributes (like product category names) alongside fact tables.
  • Audit Logging and Immutable Event Sinks: Event tables, telemetry logs, and financial transaction snapshots intentionally store denormalized copies of historical states (such as the customer's billing address at the time the order was placed) so that future address updates do not retroactively alter historic financial legal records.

Summary Checklist for Normalization in SQL

  • Ensure all table fields contain atomic values (1NF).
  • Confirm no partial dependencies on composite keys exist (2NF).
  • Remove all transitive dependencies where non-keys depend on non-keys (3NF).
  • Verify that determinants in functional dependencies are superkeys (BCNF).
  • Profile query latency and use indexing or targeted denormalization when analytics require high-speed aggregations.

Practice SQL Schema Design & Queries

Master database normalization, query optimization, and real-world analytical problems on Topfolio.

Start Free SQL Course

Frequently Asked Questions

What is normalization in SQL?

Normalization in SQL is a systematic database design technique that organizes relational tables to minimize data redundancy and eliminate insertion, update, and deletion anomalies by decomposing unnormalized tables into smaller, well-structured relationships.

What are the first three normal forms (1NF, 2NF, 3NF)?

1NF enforces atomic (indivisible) column values and unique rows. 2NF meets 1NF and removes partial dependencies where non-key attributes depend on part of a composite primary key. 3NF meets 2NF and eliminates transitive dependencies where non-key attributes depend on other non-key attributes.

What is the difference between 3NF and BCNF?

Boyce-Codd Normal Form (BCNF) is a stricter variant of 3NF. While 3NF permits non-prime attributes to be functionally dependent on superkeys or prime attributes, BCNF requires that for every functional dependency (X -> Y), X must strictly be a superkey.

When should you denormalize a database in SQL?

Denormalization is applied in read-heavy analytics platforms, reporting marts, and data warehouses (such as Star or Snowflake schemas) to reduce expensive multi-table JOIN operations and accelerate complex aggregation queries.

What are the three data modification anomalies prevented by normalization?

The three anomalies are: Insertion Anomaly (inability to insert data without unrelated attributes), Update Anomaly (data inconsistency when changing values in multiple duplicate records), and Deletion Anomaly (unintended loss of critical records when deleting related data).

Anuj Saini

Written by

Anuj SainiFounder & Lead Instructor

Founder at Topfolio with 6+ years in data & analytics across JPMC, Ultrahuman, and high-growth startups. Sat on hiring panels, reviewed 500+ resumes, and writes practical SQL & data guides.