1First Normal Form (1NF)
▶
First Normal Form, universally abbreviated as 1NF, is the foundational rule of relational database normalization. Every higher normal form builds on top of it, which means a table that violates 1NF cannot meaningfully be evaluated against 2NF, 3NF, or any of the more advanced forms. Understanding 1NF thoroughly — not just as a checklist but as a philosophy about how relational data should be structured — is essential before moving anywhere else in normalization theory.
The core idea behind 1NF comes directly from the relational model introduced by Edgar F. Codd in the 1970s. Codd's model treats a database table as a mathematical relation: a set of tuples, where each tuple represents a single fact and each attribute (column) holds a single, well-defined value. When tables deviate from this model — by cramming multiple values into one cell or by repeating the same attribute across many columns — they introduce ambiguity, redundancy, and fragility that makes the data hard to query, maintain, and trust.
A table is in 1NF when it satisfies four conditions simultaneously:
- Every column contains only atomic (indivisible) values — no lists, sets, arrays, or nested structures inside a single cell.
- Every column holds values of a single, consistent data type — every entry in a given column is of the same kind.
- Every row is unique, enforced by declaring a primary key.
- There are no repeating groups — no pattern of multiple columns that all represent different instances of the same attribute.
These four rules are deeply interrelated. A table that violates any one of them will typically violate the spirit of the others as well. Let us examine each rule and its practical implications in detail.
The Atomicity Requirement
Atomicity is the most discussed rule of 1NF. An atomic value is one that, from the database's perspective, cannot and should not be broken down further. A person's first name is atomic. A date stored as a proper DATE type is atomic. A numeric price is atomic. These are single, indivisible facts.
A non-atomic value is one where multiple pieces of information have been packed into a single field. The most common examples are comma-separated lists, space-delimited strings, JSON arrays stored in a text column, or pipe-separated codes. Consider a Students table with a Courses column that looks like this:
| StudentID | StudentName | Courses |
|---|---|---|
| 101 | Alice Marsh | Math, History, Biology |
| 102 | Ben Okafor | English, Art |
| 103 | Cora Li | Math, Physics, Chemistry, English |
The Courses column is not atomic. Each cell contains multiple course names fused together as a single string. This creates a cascade of practical problems:
- Querying is difficult. To find all students enrolled in Math, the database cannot do a simple equality check. It must search inside strings, typically using a
LIKE '%Math%'pattern, which is slow, error-prone, and will produce false positives (e.g., matching "Mathematics" when you searched for "Math"). - Indexing is impossible at the value level. A standard B-tree index on the
Coursescolumn indexes the entire string "Math, History, Biology" as one value — it cannot index the individual courses within it. - Updates are fragile. Removing Alice from History requires parsing her string, editing it, and writing it back. Any parsing error corrupts the data.
- Counting and aggregation break. How many students are enrolled in Math? There is no clean SQL to answer this without complicated string manipulation.
The fix for non-atomic data is to expand the table so that each individual value gets its own row. Every row then describes one atomic fact — one student enrolled in one course — and all the other column values are duplicated as needed to preserve context:
| StudentID | StudentName | Course |
|---|---|---|
| 101 | Alice Marsh | Math |
| 101 | Alice Marsh | History |
| 101 | Alice Marsh | Biology |
| 102 | Ben Okafor | English |
| 102 | Ben Okafor | Art |
| 103 | Cora Li | Math |
| 103 | Cora Li | Physics |
| 103 | Cora Li | Chemistry |
| 103 | Cora Li | English |
Now every cell contains exactly one value. Querying for students in Math is a simple WHERE Course = 'Math'. Indexing works perfectly. Counting enrollments per course is a straightforward GROUP BY. The data has become genuinely queryable.
It is worth noting that the definition of "atomic" is context-dependent. A full mailing address stored in one column is technically non-atomic (it contains street, city, state, and zip code), but if your application never needs to query or filter by individual parts of the address, storing it as one string may be a reasonable practical choice. Atomicity is about whether the database needs to interpret the internal structure of a value. If it never does, the value is atomic from the system's perspective. That said, when in doubt, it is almost always better to separate values — storage is cheap, and future requirements are unpredictable.
Eliminating Repeating Groups
A repeating group is a different kind of 1NF violation. Instead of hiding multiple values inside one column, a repeating group spreads multiple instances of the same attribute across multiple columns. This design pattern was common in pre-relational, flat-file systems and still appears frequently when developers design tables without normalization in mind.
Imagine an Orders table designed to hold the items within each order:
| OrderID | CustomerName | Item1 | Qty1 | Item2 | Qty2 | Item3 | Qty3 |
|---|---|---|---|---|---|---|---|
| 5001 | Alice Marsh | Notebook | 2 | Pen | 5 | NULL | NULL |
| 5002 | Ben Okafor | Stapler | 1 | Paper | 3 | Clips | 10 |
| 5003 | Cora Li | Ruler | 1 | NULL | NULL | NULL | NULL |
The columns Item1/Qty1, Item2/Qty2, Item3/Qty3 are a classic repeating group. They represent the same concept — an item in an order — just numbered to allow more than one. This design fails badly in several ways:
- It caps capacity arbitrarily. The table supports at most three items per order. The fourth item of an order has nowhere to go without altering the table schema to add
Item4andQty4. - It wastes space and creates NULLs. Orders with fewer than three items leave columns NULL, as seen in Alice's and Cora's rows. This is wasteful and makes aggregate queries awkward.
- Queries are complicated. To find every order containing a Stapler, you cannot just write
WHERE Item = 'Stapler'. You must writeWHERE Item1 = 'Stapler' OR Item2 = 'Stapler' OR Item3 = 'Stapler'— and this query would need updating every time you add a new item column. - Sorting and ranking by item is meaningless. The position of an item (Item1 vs. Item2) carries no semantic value, yet the schema implies an ordering.
The correct solution is to move the repeating group into a separate, dedicated table. The new table references the original table through a foreign key, naturally creating a one-to-many relationship:
| OrderID | CustomerName |
|---|---|
| 5001 | Alice Marsh |
| 5002 | Ben Okafor |
| 5003 | Cora Li |
| OrderItemID | OrderID | ItemName | Quantity |
|---|---|---|---|
| 1 | 5001 | Notebook | 2 |
| 2 | 5001 | Pen | 5 |
| 3 | 5002 | Stapler | 1 |
| 4 | 5002 | Paper | 3 |
| 5 | 5002 | Clips | 10 |
| 6 | 5003 | Ruler | 1 |
The Orders table now holds only order-level information. The OrderItems table holds item-level information, with each row representing one item in one order. An order can now contain any number of items without any schema changes. There are no NULLs. Querying for all orders containing a Stapler is a single WHERE ItemName = 'Stapler'. The repeating group has been eliminated and replaced with a proper relational structure.
Identifying a Primary Key
A table in 1NF must have a primary key — one column or a combination of columns (a composite key) whose values uniquely identify every row in the table. This rule is what gives "every row must be unique" its teeth. Without a primary key, the database has no reliable mechanism to address a specific row.
Two absolute rules govern primary keys:
- Uniqueness: No two rows may share the same primary key value. If
StudentIDis the primary key, no two students can have the same ID. - Non-nullability: A primary key column may never contain NULL. NULL represents an unknown or missing value — and if we do not know the identifier, we cannot reliably identify the record. Most database systems enforce this automatically when you declare a column as
PRIMARY KEY.
When transforming an unnormalized table into 1NF, you must explicitly identify or create an appropriate primary key. In many cases, the original table may not have a clear natural key after the transformation (especially when rows have been split), so introducing a surrogate key — an artificial, system-generated integer identifier — is common and perfectly acceptable.
Consider the flattened Students/Course table from earlier. After splitting, StudentID alone is no longer unique (Alice appears three times). The primary key for that table must be the combination of StudentID and Course, because together they uniquely identify each enrollment row:
PRIMARY KEY (StudentID, Course)
Alternatively, a surrogate key EnrollmentID could be introduced as an auto-incrementing integer, making each row uniquely addressable by a single column. Either approach is valid; the choice depends on the broader design requirements of the system.
Transforming an Unnormalized Table into 1NF: Step-by-Step
Let us consolidate everything into a clear, repeatable process. Given any unnormalized table, apply these five steps to bring it into 1NF:
- Step 1 — Identify non-atomic columns. Examine every column and look for cells that contain multiple values. Telltale signs include comma-separated strings, slash-delimited codes, semicolon-separated names, or free-text fields that encode structured information. Any such column violates atomicity and must be fixed.
- Step 2 — Identify repeating groups. Look for families of similarly named columns — anything following a pattern like
Phone1,Phone2,Phone3orAddress_Line1,Address_Line2where the intent is to store multiple instances of the same concept. These must be extracted into a child table. - Step 3 — Flatten the data. For each non-atomic column, split the multi-valued cell into individual rows. Duplicate the values of all other columns in each new row as needed to preserve the context. For repeating groups, create a new table with a foreign key pointing back to the parent table, and move each instance into its own row in that new table.
- Step 4 — Define a primary key. After flattening, determine which column or combination of columns uniquely identifies each row. Declare this as the primary key. If no natural candidate exists, introduce a surrogate key.
- Step 5 — Verify compliance. Do a final check: every cell should contain exactly one atomic value; every row should be unique (provable by the primary key); no column should be NULL-heavy in a way that suggests a repeating group; and no column should be a delimited list.
Before and After: A Complete 1NF Example
To bring all of these concepts together, consider the following unnormalized StudentCourses table from a school's legacy system:
| StudentID | StudentName | Advisor | Course1 | Grade1 | Course2 | Grade2 | Course3 | Grade3 |
|---|---|---|---|---|---|---|---|---|
| 101 | Alice Marsh | Dr. Reed | Math | A | History | B+ | NULL | NULL |
| 102 | Ben Okafor | Dr. Pham | English | B | Art | A- | Physics | C+ |
| 103 | Cora Li | Dr. Reed | Chemistry | A+ | NULL | NULL | NULL | NULL |
This table has a clear repeating group: the Course1/Grade1, Course2/Grade2, Course3/Grade3 triplets. It is capped at three courses per student, contains numerous NULLs, and makes it impossible to efficiently query "which students received an A in any course?" without checking all three grade columns.
Applying the five steps:
- No non-atomic columns are present (each individual cell holds one value), so Step 1 reveals no comma-separated lists. However, Step 2 reveals the obvious repeating group.
- We create a separate
Enrollmentstable and move the course/grade pairs there, each as its own row. - The
Studentstable retains only student-level data, withStudentIDas its primary key. - The
Enrollmentstable uses a composite primary key of(StudentID, CourseName), since a student can only have one grade per course.
The resulting 1NF-compliant Students table:
| StudentID | StudentName | Advisor |
|---|---|---|
| 101 | Alice Marsh | Dr. Reed |
| 102 | Ben Okafor | Dr. Pham |
| 103 | Cora Li | Dr. Reed |
The resulting 1NF-compliant Enrollments table:
| StudentID | CourseName | Grade |
|---|---|---|
| 101 | Math | A |
| 101 | History | B+ |
| 102 | English | B |
| 102 | Art | A- |
| 102 | Physics | C+ |
| 103 | Chemistry | A+ |
The transformation has several immediate benefits. The total row count grew from 3 to 6 (in Enrollments), but every row now represents exactly one logical fact: one student's grade in one course. All NULLs are gone. A query like "find all students who earned an A" is now simply:
SELECT s.StudentName, e.CourseName
FROM Students s
JOIN Enrollments e ON s.StudentID = e.StudentID
WHERE e.Grade = 'A';
This is clean, readable, and fully indexable. There is no limit on how many courses a student can enroll in — adding a fourth course is just a new row in Enrollments, not a schema change. The data is now a proper foundation on which Second Normal Form and beyond can be applied.
It is important to understand that 1NF does not, by itself, eliminate all redundancy. Notice that Dr. Reed appears twice in the Students table. Removing that kind of redundancy is the job of higher normal forms. But 1NF is the essential prerequisite — it establishes that the data is structured as a proper relational table in the first place, with clean atomic values, unique rows, and no hidden multi-valued columns. Everything else in normalization theory depends on this foundation being solid.