如何将数据库规范化至3NF?关于joistcost等字段的处理困惑求助
Got it, let's break this down step by step because normalizing to 3NF when you have calculated fields can feel tricky at first! The core principle here is that 3NF strongly discourages storing derived/calculated values—these should be computed on the fly instead of saved directly, since stored calculated data creates redundancy and update anomalies (like if you change joistcost but forget to update floorcost, your data becomes inconsistent immediately).
Let’s start with your specific fields and map them to a 3NF-compliant structure:
joistcost: Single component cost (this is a raw, non-derived value—we keep this, but in the right table)floorcost:joistcost * width(derived value—do NOT store this)projecttotal: Sum of allfloorcostfor a project (also derived—do NOT store this)
Step 1: Split data into logical, single-purpose tables
We need to eliminate redundancy and ensure each table only holds data tied to one entity:
joiststable (stores component master data)- Columns:
joist_id(primary key),joist_type(e.g., "steel I-joist", "wood joist"),joist_cost(yourjoistcostfield—single unit cost) - Why? This way, each component’s cost is stored exactly once, not repeated for every floor that uses it. No redundant copies mean no sync issues later.
- Columns:
projectstable (stores project-level details)- Columns:
project_id(primary key),project_name,client_name,start_date, etc. (any attributes specific to the entire project)
- Columns:
floorstable (links projects to components, stores floor-specific data)- Columns:
floor_id(primary key),project_id(foreign key linking toprojects.project_id),joist_id(foreign key linking tojoists.joist_id),floor_width(the width value used to calculatefloorcost) - Why? Each floor belongs to one project, uses one joist type, and has its own width. We don’t store
floorcosthere because we can calculate it by joining with thejoiststable.
- Columns:
Step 2: Calculate your "missing" fields when you need them
Instead of storing floorcost and projecttotal, compute them with queries whenever you need the data:
To get a single floor’s
floorcost:SELECT f.floor_id, j.joist_cost * f.floor_width AS floorcost FROM floors f JOIN joists j ON f.joist_id = j.joist_id WHERE f.floor_id = [your_floor_id];To get a project’s total
projecttotal:SELECT p.project_id, p.project_name, SUM(j.joist_cost * f.floor_width) AS projecttotal FROM projects p JOIN floors f ON p.project_id = f.project_id JOIN joists j ON f.joist_id = j.joist_id WHERE p.project_id = [your_project_id] GROUP BY p.project_id, p.project_name;
Step 3: Confirm this fits 3NF rules
Let’s verify against the three normal forms:
- 1NF: All columns have atomic values (yes—each field holds one discrete piece of data, no repeating groups)
- 2NF: No partial dependencies (all non-primary key columns depend entirely on the table’s primary key. For example, in
floors,project_id,joist_id, andfloor_widthall rely onfloor_id; injoists,joist_costdepends solely onjoist_id) - 3NF: No transitive dependencies (no non-primary key column depends on another non-primary key column. Since
joist_costlives in thejoiststable, there’s no indirect dependency betweenfloor_widthandjoist_costin thefloorstable)
This setup keeps your data consistent, cuts down on redundant storage, and avoids the headache of updating calculated values every time a raw value changes. If you ever need to adjust a joist’s cost, you only update it once in the joists table—all future calculations will automatically use the new value.
内容的提问来源于stack exchange,提问作者rbittle2

