First Normal Form
Imagine a university database storing student records where a `phones` column holds `"555-1234, 555-9876"` in a single cell. A query asking "which students share a phone number with another student" becomes a nightmare of string parsing. It should be a simple join instead. This is the core problem First Normal Form (1NF) exists to eliminate. It demands that every attribute value in a relation be a single, indivisible unit. This ensures the relational model's mathematical guarantees actually hold: set-based query languages, predictable joins, well-defined keys. 1NF is the entry gate to the relational model itself. A table that violates 1NF is not merely "badly designed." In the strict relational sense, it is not a relation at all. This is because relations are built on domains of atomic values. Real database systems historically diverged here. Strict SQL engines rejected repeating groups outright. Modern systems (PostgreSQL arrays, JSON columns, nested/struct types in Spark and BigQuery) reintroduce structured values deliberately. They trade some 1NF purity for expressiveness. Understanding 1NF precisely lets you recognize something important. You can tell when a "nested" design is a genuine denormalization tradeoff. You can also tell when it is an accidental anomaly generator instead. This article follows directly from Normalization Motivation and Anomalies. There, update, insertion, and deletion anomalies were introduced as symptoms of poor schema design. 1NF is the first and most basic normal form. It addresses a narrower but foundational anomaly: multi-valued or composite attributes. These break the atomic-value assumption baked into the relational model. It sets the stage for Second Normal Form and Third Normal Form. Those tackle anomalies arising from functional dependencies rather than attribute structure. By the end of this article you will gain several skills. You will be able to state the formal definition of 1NF precisely. You will detect violations in a schema. You will apply the standard decomposition algorithm to fix them. You will also reason about why atomicity is a prerequisite — not an alternative — to the deeper normal forms that follow.
- 1NF requires every attribute value to be atomic (indivisible) and drawn from a single scalar domain — no repeating groups, no nested tables, no multi-valued cells.
- A relation violating 1NF typically has a "list" or "set" hidden inside a column, or a repeating group of columns like `phone1, phone2, phone3`.
- The fix is decomposition: pull the repeating/multi-valued attribute into a separate relation connected by a foreign key, or flatten a fixed repeating group into rows.
- 1NF is necessary for the relational algebra and SQL's set semantics to behave correctly under selection, projection, and join.
- Modern systems (arrays, JSON, nested structs) deliberately break strict 1NF for performance or convenience — this is a conscious tradeoff, not a bug, but it reintroduces classic anomalies.
- 1NF is a prerequisite for Second Normal Form and Third Normal Form, which assume atomic attributes and instead reason about functional dependencies.
A relation is in First Normal Form exactly when every attribute value in every tuple is a single atomic value from its domain — no lists, sets, or nested records hiding inside a cell.
The idea
A relation in the relational model is formally a subset of the Cartesian product of a list of domains , where each domain is a set of atomic values. "Atomic" means the values in are treated as indivisible units by the model — you cannot ask the relational algebra to reach inside a domain value and extract part of it. A telephone number `"555-1234"` stored as a single string is atomic in this sense even though it "contains" digits, because the schema treats it as one value; the trouble starts when a single attribute is asked to hold a variable number of values, such as `{"555-1234", "555-9876"}` for a student with two phones.
First Normal Form (1NF) is the constraint that a relation's domains contain only atomic values, equivalently: every attribute of every tuple holds exactly one value, never a set, list, or nested tuple. A schema that permits a repeating group — a set of columns like `phone1, phone2, phone3` meant to hold "however many phones this row has, up to three" — or a multivalued attribute — a single column meant to hold an unbounded collection — is not in 1NF. Neither is a schema with a composite attribute stored as one nested record, e.g., an `Address` column that is itself a struct of `{street, city, zip}`, if the intent is that sub-fields should be independently queryable and constrained. The distinction that matters is between representation and semantics. A `VARCHAR` column holding `"123 Main St, Springfield, 62704"` is technically atomic (one string) but semantically composite, and treating it as opaque prevents the database from enforcing constraints like "zip code determines city" or indexing on zip alone. 1NF violations, therefore, come in two flavors: multi-valued (a cell holds a variable-length collection) and composite/non-atomic (a cell holds a fixed internal structure the application still needs to decompose). Both break the guarantee that selection, projection, and join operate correctly and predictably over single-valued comparisons.
How it works
Detecting and fixing a 1NF violation follows a standard recognition-and-decomposition pattern. The core test is: for a given attribute, can a single tuple legitimately need to store more than one value, or a structured value, in that attribute's cell? If yes, the schema is not in 1NF. The two structural symptoms: 1. Repeating groups as columns. `Student(ID, Name, Phone1, Phone2, Phone3)`. This wastes space for students with fewer phones, cannot accommodate a fourth phone, and makes "find all phones for this student" awkward (you must check three columns). 2. Multi-valued single column. `Student(ID, Name, Phones)` where `Phones = "555-1234, 555-9876"`. This makes it impossible to declare a domain, index individual phone numbers, or enforce uniqueness of a phone number across students without string parsing. The standard fix is decomposition into a separate relation connected by the original key, turning the "many values in one cell" problem into "many rows in a child table" — which the relational model handles natively via foreign keys and joins. ``` ALGORITHM DetectAndFix1NF(R, attributes) // R: a relation schema with a candidate/primary key K // attributes: list of (name, domain_description) pairs violations := [] FOR EACH attr IN attributes: IF attr.domain_description indicates "set of values" OR attr.domain_description indicates "variable-length list" OR attr is one of a numbered repeating group {A1, A2, ..., Ak}: violations.append(attr) IF violations is empty: RETURN R // already in 1NF, nothing to do FOR EACH attr IN violations: IF attr is a numbered repeating group {A1, ..., Ak}: // Case 1: fixed repeating group -> flatten to rows newRelation := CREATE RELATION R_attr(K, attr_value) FOR EACH tuple t IN R: FOR i IN 1..k: IF t.A_i IS NOT NULL: INSERT (t.K, t.A_i) INTO R_attr REMOVE columns A1..Ak FROM R ELSE: // Case 2: single multi-valued column -> split values into rows newRelation := CREATE RELATION R_attr(K, attr_value) FOR EACH tuple t IN R: FOR EACH value v IN SPLIT(t.attr, delimiter): INSERT (t.K, v) INTO R_attr REMOVE column attr FROM R RETURN {R (with violations removed), R_attr for each violation} ``` Applied to `Student(ID, Name, Phone1, Phone2, Phone3)`: ``` Student(ID, Name) StudentPhone(ID, Phone) -- one row per (student, phone) pair -- FOREIGN KEY ID REFERENCES Student(ID) ``` The composite-key of `StudentPhone` is `(ID, Phone)`, since a student may have several phones and — in principle — a phone could be shared (though a `UNIQUE` constraint might forbid that depending on business rules). This is the general recipe: whenever an attribute is multi-valued relative to the key, split it into its own relation whose key includes the original key plus the value itself (or a synthetic surrogate). The same reasoning applies to composite attributes that need independent access: `Address` becomes `Street, City, Zip` as three atomic columns directly in the same relation (no new relation needed, since a composite attribute is not multi-valued — it just needs its parts named separately).
Complexity & correctness
Detection complexity. Detecting whether a schema is in 1NF is a syntactic check on the schema definition, not on data: for each attribute, inspect whether its declared domain is atomic (a single scalar type) or structured (an array, set, nested record, or a numbered family of columns). This is in the number of attributes in the relation — a linear scan of the schema, no data access required. Detecting accidental non-atomicity in already-atomic-typed columns (e.g., a `VARCHAR` secretly storing a comma-separated list) additionally requires a data scan, in the number of tuples , to check whether values match a "single item" pattern versus a delimited list — this is a heuristic, not a formal guarantee, since nothing in the schema prevents a legitimate atomic string from containing a comma.
Decomposition complexity. The `DetectAndFix1NF` algorithm above performs one pass over the relation's tuples, and for each tuple, a constant amount of work per repeating-group slot or a split proportional to the number of values in the multi-valued cell. If a relation has tuples and each tuple's multi-valued attribute contains at most values, total work is — each value is written exactly once into the new child relation, so this is optimal: you cannot produce the output (one row per value) in less than the size of the output.
Space. The decomposed schema does not necessarily increase total data volume; it trades wasted NULL cells (in the repeating-group version, most rows have unused `Phone2`, `Phone3` slots) for a compact child table with exactly one row per actual value. In the worst case (every student has exactly the maximum number of phones), space is comparable; in the common case (variable number of values), the 1NF decomposition is strictly more space-efficient because it eliminates NULL padding.
Correctness argument. The key claim is that decomposition is lossless — the original relation can be exactly reconstructed by projecting and joining the decomposed pieces. This follows because the child relation retains the parent's key (`ID`) alongside the split-out value, so:
reconstructs the same information via a natural join on `ID` (formally, you would need an outer join if some students have zero phones, to preserve rows with no matching child tuples — a subtlety worth flagging explicitly). This is an instance of the general lossless-join decomposition criterion used throughout normalization theory: a decomposition of into is lossless if is a superkey of at least one of . Here , and `ID` is (part of) the key of both — trivially satisfying the criterion for the parent side, and being a foreign key referencing it on the child side.
Why atomicity is necessary, not cosmetic. The relational algebra's selection operator assumes is a predicate over single values (e.g., `Phone = '555-1234'`); if `Phone` can hold `"555-1234, 555-9876"`, this predicate silently fails to match a tuple that logically does contain that phone number, unless you rewrite every query with substring search — abandoning the declarative guarantees SQL is supposed to provide. Similarly, a `GROUP BY Phone` or `JOIN ON Phone` becomes meaningless across multi-valued cells: two students who share one phone number out of several would not be correctly grouped together by naive equality. 1NF is precisely the condition under which `=` comparison and the standard relational operators behave as the algebra's semantics promise.
Honest tradeoff. Strict 1NF is not free. Splitting one multi-valued attribute into a child relation means every query needing "students and their phones together" must perform a join, adding I/O and CPU cost proportional to the join algorithm used (commonly for sort-merge join, or expected for hash join) versus access to a denormalized array cell. This is exactly why systems like PostgreSQL (array types), MongoDB (embedded documents), and BigQuery (nested/repeated fields) offer controlled, first-class support for non-atomic values — accepting some anomaly risk in exchange for avoiding join overhead in read-heavy, write-rarely workloads.
Worked example
Consider an unnormalized `CourseEnrollment` table meant to record, for each student, the courses they are taking and the courses' instructors:
| StudentID | StudentName | Courses |
|---|---|---|
| 101 | Ada | `{("CS101", "Turing"), ("CS201", "Hopper")}` |
| 102 | Grace | `{("CS201", "Hopper")}` |
| 103 | Alan | `{}` |
The `Courses` attribute is a set of nested pairs — doubly non-atomic: it is multi-valued (a student can take several courses) and each value is itself composite (a course-instructor pair). This is a realistic pattern seen in document stores and JSON columns, and it is the sharpest kind of 1NF violation because naive flattening alone is insufficient — we must both split the set and decompose the pairs.
Step 1 — split the multi-valued attribute into rows, keeping `StudentID` as the linking key:
| StudentID | Course | Instructor |
|---|---|---|
| 101 | CS101 | Turing |
| 101 | CS201 | Hopper |
| 102 | CS201 | Hopper |
(Student 103, with an empty set, contributes no rows here — a consequence worth noting: information about "Alan exists but takes nothing" now lives only in the `Student` table, which is correct and expected.)
Step 2 — separate the base relation:
| StudentID | StudentName |
|---|---|
| 101 | Ada |
| 102 | Grace |
| 103 | Alan |
Step 3 — verify atomicity. Every column in both resulting relations now holds exactly one scalar value per row: `StudentID` is an integer, `Course` is a course code string, `Instructor` is a name string. No cell contains a set or a nested structure. Both relations are in 1NF.
Step 4 — verify losslessness. Reconstructing the original requires an outer join of `Student` and `Enrollment` on `StudentID`, then grouping `Enrollment` rows back into a set per student — recovering exactly the original nested structure (including Alan's empty set, thanks to the outer join). No information was discarded; only its physical shape changed. Notice a side effect: this decomposition has silently also produced a table, `Enrollment(StudentID, Course, Instructor)`, that is ripe for a different kind of anomaly — if `Hopper` is misspelled in one row and not another, we get an inconsistency, because `Instructor` depends only on `Course`, not on the full key `(StudentID, Course)`. This is a partial dependency, and it is exactly the problem Second Normal Form is designed to catch; 1NF's job ends at making the attributes atomic, not at eliminating every anomaly.
Common pitfalls & traps
| Pitfall | Why it happens | Consequence |
|---|---|---|
| Treating a delimited string (`"a,b,c"`) as atomic because it's stored as `VARCHAR` | Confusing physical type with logical content | Cannot query, index, or constrain individual values without string parsing; classic hidden 1NF violation |
| "Fixing" 1NF by adding more numbered columns (`Phone4`, `Phone5`) | Underestimating how many values might occur | Schema still capped, still wastes space, still not in 1NF — a repeating group with a higher bound is still a repeating group |
| Forgetting the outer join when reconstructing decomposed data | Assuming every parent row has at least one child row | Silently drops parent rows with zero associated values (e.g., students with no enrolled courses) |
| Splitting a multi-valued and composite attribute in one step without separating the two concerns | Rushing the decomposition | Ends up with a child table that still bundles unrelated facts, reintroducing anomalies 2NF/3NF must later fix |
| Assuming 1NF alone eliminates all update anomalies | Conflating 1NF with "fully normalized" | 1NF only fixes atomicity; functional-dependency-based anomalies (partial and transitive dependencies) remain and require 2NF/3NF |
Pioneers & history
The relational model, and with it the first formal statement of normal forms, originates with Edgar F. Codd's foundational 1970 paper proposing that data be represented purely as relations over atomic domains — a radical simplification compared to the hierarchical and network database systems of the era, which natively supported nested and repeating structures. Codd's insistence on atomic domains was not incidental; it was the precondition that made relational algebra a clean, closed algebraic system in the first place. Without atomicity, operators like selection and join lose their precise mathematical meaning, and the whole appeal of a declarative query language built on set theory collapses.
Origins · 1 minEdgar F. Codd and how this was discovered
Where this matters
Every production relational database — PostgreSQL, MySQL, Oracle, SQL Server, SQLite — enforces 1NF by construction in its base table storage model: a column is declared with a single scalar type, and standard `CREATE TABLE` syntax has no way to express "a variable number of values" without an explicit array or JSON type. Schema designers doing entity-relationship modeling for e-commerce (order line items), healthcare (patient medications), and finance (transaction tags) routinely hit the "one-to-many attribute" problem this article addresses, and the standard fix — a child table with a foreign key — is the single most common pattern in relational schema design. The tension between strict 1NF and practical convenience shows up directly in modern engines: PostgreSQL's array and `hstore` types, SQL Server's XML columns, and nearly every NoSQL document store (MongoDB, Couchbase) allow developers to deliberately store non-atomic values for performance, at the cost of reintroducing the very anomalies normalization guards against — inconsistent duplicated data, awkward uniqueness constraints, and query complexity. Data warehouse systems like BigQuery and Snowflake explicitly support nested/repeated (`STRUCT`, `ARRAY`) columns because analytical workloads often favor denormalized, pre-joined data for read performance, showing that 1NF is best understood as a design default to deviate from consciously, not an inviolable law. Understanding 1NF precisely is what lets an engineer recognize the difference between a deliberate denormalization decision and an accidental design flaw.
Ask the tutor: How does the choice between a strict 1NF design and a denormalized JSON/array column affect join cost versus anomaly risk in a real read-heavy analytics workload?
Is a table with a VARCHAR column automatically in 1NF?
Not necessarily. The SQL type system only checks that the column holds one string value, but nothing prevents that string from encoding multiple logical values, such as `"555-1234,555-9876"`. Formal 1NF is a semantic property about the domain of meaningful, indivisible values, not merely a syntactic property of the declared column type. A schema reviewer must look at what the data actually represents, not just what type it is declared as, to judge true 1NF compliance. This is the most common source of accidental 1NF violations in real schemas.
Does using an array or JSON column always violate 1NF?
Yes, strictly speaking — an array or JSON column stores a variable number of values or a nested structure in one cell, which is exactly what atomic-domain relations forbid. Many modern systems (PostgreSQL arrays, BigQuery nested fields, MongoDB documents) support this deliberately, trading strict 1NF compliance for query convenience or analytical performance on read-heavy workloads. This is a conscious engineering tradeoff, not an oversight, but it reopens the anomaly risks 1NF exists to prevent, such as inconsistent duplicate values buried inside nested structures.
What is the difference between a repeating group and a multi-valued attribute?
A repeating group is a fixed number of numbered columns meant to represent a variable-length list, like `Phone1, Phone2, Phone3`. A multi-valued attribute is a single column whose cell can hold a variable number of values, like a comma-separated string or an array type. Both violate 1NF for the same underlying reason: a single conceptual attribute is being asked to represent more than one value per tuple. The fix for both is identical — decompose into a separate relation with one row per value, linked back by the original key.
Can a relation violate 1NF and still return correct query results some of the time?
Yes, and this is precisely what makes 1NF violations dangerous rather than immediately obvious. A query like `SELECT FROM Student WHERE Phone = '555-1234'` on a multi-valued `Phone` column will simply fail to match rows where that phone number is present but not the only* value stored, silently returning incomplete results rather than an error. There is no runtime failure to alert a developer, only quietly wrong answers, which is why 1NF violations are often discovered late, during a data quality audit rather than at query-writing time.
How does 1NF relate to Second Normal Form and Third Normal Form?
1NF is a prerequisite: both 2NF and 3NF are defined only for relations that are already in 1NF, because their definitions reason about functional dependencies between whole attributes, which presupposes those attributes hold single atomic values. 2NF eliminates partial dependencies (a non-key attribute depending on only part of a composite key), and 3NF eliminates transitive dependencies (a non-key attribute depending on another non-key attribute). Neither concept is even well-defined if an attribute's "value" could itself be a set or nested structure, which is why normalization theory is presented as a strict hierarchy starting from 1NF.
Does achieving 1NF eliminate all update, insertion, and deletion anomalies?
No — 1NF only removes anomalies caused by non-atomic attribute values, such as the impossibility of adding a fourth phone number or the awkwardness of searching within a packed string. Anomalies caused by functional dependencies among atomic attributes, like a redundantly repeated instructor name for every enrollment row of the same course, persist after 1NF and require Second Normal Form and Third Normal Form to resolve. Treating 1NF as a complete fix is a common misunderstanding; it is the necessary first step, not the destination.
Why did older database models (hierarchical, network) not require 1NF?
Pre-relational systems like IBM's IMS (hierarchical model) and the CODASYL network model were built around explicit parent-child pointer structures, so nested and repeating data were native, expected constructs rather than violations of anything. Codd's relational model deliberately rejected this in favor of flat, atomic-domain tables specifically to gain a clean mathematical foundation — relational algebra and later SQL — at the cost of requiring explicit joins to represent what those older models expressed natively as nesting. 1NF is thus best understood as a defining constraint of the relational model itself, not a universal law of good data representation.