An entity in your model has an attribute that can hold several values at once, such as a customer's phone numbers. How is that mapped to relational tables, and why not use repeated columns or one comma-separated string?
answer
- multivalued attribute -> child table
- PK = (owner key, value)
- repeating columns cap the count
- CSV kills typing, FKs, uniqueness
- values gain attributes -> becomes an entity
basics
~20 sIt becomes a child table holding the owner's key plus one value per row, with a foreign key to the owner and a key over (owner key, value). Repeated columns cap the count and scatter one fact; a delimited string loses typing, constraints and lookups.
solid answer
~60 sThe mapping rule is: a multivalued attribute becomes its own table. It holds the owner entity's primary key and a single column for the value, one row per value. The owner key is a foreign key back to the parent, and the primary key is the owner key plus the value, which also prevents the same value being recorded twice for one owner. The alternatives fail for concrete reasons. **Repeated columns** — phone1, phone2, phone3 — fix an arbitrary limit, spread one logical fact across several columns so every query has to check all of them, and make adding a fourth value a schema change. **A delimited string** gives up per-value typing and validation, foreign keys, uniqueness and any usable lookup, and turns an insert into string manipulation. The child table has none of those limits, and it is also the natural growth path: as soon as each value needs facts of its own — phone type, verified flag, primary flag — you add columns to a table that already exists rather than redesigning.
code
sql · 5 linesCREATE TABLE customer_phone (
customer_id BIGINT NOT NULL REFERENCES customer(customer_id),
phone VARCHAR(30) NOT NULL,
PRIMARY KEY (customer_id, phone)
);go deeper
State the rule — child table with owner key plus value — and name at least one concrete failure of the comma-separated alternative.
Give the primary key and foreign key precisely, and explain why repeating columns are the repeating group normalisation removes.
Cover the growth path to a value with its own attributes or to a junction against a controlled vocabulary, plus ordering and duplicate questions.
Discuss the narrow cases where an array or document column is justified and what constraint and integrity guarantees you are trading away.
## The rule A multivalued attribute is one that holds a set of values for a single entity instance at the same time: phone numbers, email addresses, tags, skills. The relational model has no place to put a set inside a single value, so the mapping algorithm gives every multivalued attribute its own table. That table contains the owner's primary key plus one column per value component. Its primary key is the owner key together with the value, and the owner key is a foreign key to the parent table. Reading the owner's values is a single lookup by owner key. ## Why not repeated columns phone1, phone2, phone3 is called a repeating group and it is the shape normalisation exists to remove. The problems are practical: - The maximum is baked into the schema, and the fourth value requires a migration. - One logical fact lives in several columns, so "find the customer with this number" has to test each column, and adding a column silently breaks every such query. - Constraints and uniqueness cannot be stated once; they have to be repeated per column, and across columns they cannot easily be stated at all. - Most rows waste the unused columns, and there is no meaningful order or identity to the slots. ## Why not a delimited string Storing "555-1234,555-9876" in a single column looks compact and fails on everything the database is for. The values are not individually typed, so nothing stops a malformed entry. They cannot be foreign keys, so referencing another table is impossible. Uniqueness per value cannot be enforced. Lookups become substring matches, which are both inefficient and wrong — searching for 555-123 matches 555-1234. Adding or removing one value requires reading, parsing, editing and rewriting the whole string, which is also a concurrency hazard when two writers do it at once. ## The child table in practice Beyond correctness, the child table is the design that keeps its options open. Two extensions arrive almost every time: **Each value gains attributes.** A phone number acquires a type, a verified timestamp, a preferred flag. In a child table these are new columns. In a delimited string they are impossible without encoding structure inside the text. **The values become shared.** If the values start referring to something the business manages separately — skills from a controlled vocabulary, tags from a tag catalogue — the child table turns into a junction table by replacing the value column with a foreign key. That is a small change from a child table and a rewrite from a string column. At that point the multivalued attribute has effectively become an entity, which is the same continuum described in the conceptual model: bare set of values, then values with their own facts, then a full entity. ## Ordering and duplicates Two questions are worth asking explicitly during the mapping. Does the order of the values carry meaning? If it does, add an explicit sequence column rather than relying on insertion order, because a table has no inherent row order. Are duplicate values legitimate for one owner? Usually not, which is why the owner-plus-value primary key is a good default — but if they are, the key needs another component. ## The honest exception Modern engines offer array and document column types, and they are occasionally the right call for a small, private, unshared, unqueried, unconstrained list. Even then the tradeoff is real: you give up per-value constraints and referential integrity, and you inherit whatever query syntax that type imposes. The default remains a child table, and "I would use a child table unless the list is small, private and never searched" is a stronger answer than either dogma.
- What changes if each phone number also needs a type and a verified flag?Nothing structural — they become extra columns on the child table. That is the point of mapping the multivalued attribute to a table in the first place: the value has grown into something with its own facts, and the table already gives those facts a home. Conceptually the attribute has become an entity in its own right.
- Is a native array or JSON column ever an acceptable alternative?Occasionally, for a small list that is private to the row, never referenced by other tables, never individually constrained, and never searched on its own. Even then you lose per-value typing, foreign keys and uniqueness, and you take on the engine's array or document query syntax. Anything filtered, joined or validated per value should be a child table.
saying these in an interview costs you the question
- Proposing a comma-separated string because it is 'simpler' and can be split in application code
- Adding numbered columns and treating the resulting limit as acceptable
- Omitting the foreign key back to the owner, leaving orphan rows possible
- Assuming a child table implies the values are ordered, without adding an explicit sequence column
- Treating the child table as a heavyweight over-design for something the database is built to do