Module 2 · Data Modelling
Entities, attributes and grain
Turn things into tables and facts into columns, choose data types, and state the grain - what one row means.
About 25 minutes
The problem
Kolanut wants to store its customers properly. Someone suggests one column called details holding "Peace Provisions, Kiosk, Kano, rep 7". It's easy to type, and impossible to filter, count or join. Deciding what the table is, which columns it has, and what one row means is the core skill of modelling.
The concept
An entity is a kind of thing the business stores data about: customers, products, invoices. Each entity becomes a table.
An attribute is one fact about that thing: a customer's name, channel, region. Each attribute becomes a column, with one data type.
An instance is one particular thing: one customer. It becomes a row.
Rules for good attributes
- One fact per column. Not
"Kano, North West"; usecityandregion. - One value per cell. Not
"Malt drink, Chin chin"; that's two rows of something else. - The right data type. Numbers you calculate with are numbers; dates are dates; IDs and phone numbers are text or integers you never add up. (
08031234567stored as a number loses its leading zero.) - Clear names.
customer_name, notname2orCustNm.
Common data types
| Type | For | Examples |
|---|---|---|
| Integer | Counts and IDs | quantity, customer_id |
| Decimal / money | Amounts | unit_price, amount_ngn |
| Text | Names, codes, categories | region, phone |
| Date / datetime | When something happened | order_date |
| Boolean | Yes / no | is_active |
Grain is the answer to what does one row represent? Always state it in one sentence:
customers: one row per customer.orders.csv: one row per product on an order (an order line), not one row per order.attendance.csv: one row per employee per working day.
Most double-counting mistakes are grain mistakes: summing a customer's credit limit across their order lines, or counting order lines as orders.
Example
Harbourline's shipments table: one row per shipment. It has 2,683 rows but only 105 different customers, because customers book many shipments:
SELECT COUNT(*) AS shipments,
COUNT(DISTINCT customer_id) AS customers_who_booked
FROM shipments;Walkthrough
Designing Kolanut's product table, step by step:
- Entity: product. Grain: one row per product (one pack size of one item).
- Attributes: name, category, list price. Brand and pack size could be separate columns if managers filter by them.
- Types:
product_idinteger,product_nametext,categorytext,list_pricemoney. - Check against a question: "Revenue by category": category must be a clean column with a fixed list of values. ✓
Practice
Practice
Complete the grain of Kolanut's orders.csv: one row per ___ on one order. (One word.)
Practice
Harbourline's `payments` table: return the number of payment rows and the number of **different shipments** they pay for, as two columns.
Ctrl + Enter to run. Tab indents; press Esc then Tab to leave the editor.
Check your understanding
Answer every question to check.