Relational Database Fundamentals¶
In a relational model, data is held in relations, usually implemented as tables. A table has named columns; each row represents one fact of the table’s type. Tables refer to each other with keys instead of nesting arbitrary records inside one another.
An RDBMS—such as PostgreSQL, MySQL, SQL Server, or SQLite—does more than save tables. It parses SQL, plans queries, coordinates concurrent work, enforces constraints, records changes durably, and supports backup and recovery.
From ERD to schema¶
The straightforward mapping is:
| ERD idea | Relational implementation |
|---|---|
| Entity | Table |
| Attribute | Column |
| Entity instance | Row |
| Identifier | Primary key |
| One-to-many relationship | Foreign key on the “many” table |
| Many-to-many relationship | Junction table with two foreign keys |
| Business rule | Constraint, transaction rule, or application rule |
For example, the relationship “a customer places orders” becomes an orders.customer_id column that refers to customers.customer_id.
CREATE TABLE customers (
customer_id UUID PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
display_name TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE orders (
order_id UUID PRIMARY KEY,
customer_id UUID NOT NULL REFERENCES customers(customer_id),
status TEXT NOT NULL,
placed_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
The database now rejects an order with no customer or with a customer ID that does not exist. That is more reliable than hoping every caller remembered to check first.
Schema, table, row, and column¶
A schema is a namespace and a contract for database objects. In a small application, public might contain everything. In a larger system, schemas can group modules such as billing, catalog, or reporting; they are not a replacement for service ownership boundaries.
| Term | Example |
|---|---|
| Database | store_production |
| Schema | sales |
| Table | sales.orders |
| Row | One order, identified by order_id |
| Column | status, placed_at, customer_id |
| Value | paid, 2026-09-17T10:00Z, a UUID |
Choose types that express meaning¶
Types are part of correctness. Pick types for the data’s semantics and expected operations, not merely what is convenient in the application language.
| Kind of fact | Typical type | Notes |
|---|---|---|
| Identifier | UUID, BIGINT |
See key strategy on the next page |
| Small whole count | INTEGER |
Add a positive check when appropriate |
| Money | NUMERIC(p,s) or integer minor units |
Never use binary floating point for exact currency |
| Time of an event | TIMESTAMPTZ |
Store an instant with timezone-aware semantics |
| Calendar date | DATE |
A birthday is not an instant |
| Bounded state | TEXT + CHECK, enum, or lookup table |
Choose based on how often values change |
| Flexible metadata | JSONB/JSON where supported |
Do not use it to avoid modeling core relational facts |
Database type names and details vary by product. The SQL examples in this tutorial are PostgreSQL-flavoured, but the relational ideas apply broadly.
NULL means unknown or inapplicable¶
NULL does not mean an empty string, zero, or “false.” It means no value is present—often because it is unknown or not applicable. SQL’s three-valued logic makes this matter:
-- This does not return rows where cancelled_at is NULL.
SELECT * FROM orders WHERE cancelled_at = NULL;
-- This does.
SELECT * FROM orders WHERE cancelled_at IS NULL;
Make a column NOT NULL when the business rule requires a value. Do not make fields nullable merely to make early inserts easier; model draft state or a separate workflow if that is what exists.
SQL is declarative¶
With SQL, describe the result you want, not the loops used to get it.
SELECT o.order_id, o.placed_at, o.status
FROM orders AS o
JOIN customers AS c ON c.customer_id = o.customer_id
WHERE c.email = 'ada@example.com'
AND o.placed_at >= CURRENT_DATE - INTERVAL '30 days'
ORDER BY o.placed_at DESC;
The RDBMS chooses a plan based on table statistics, constraints, and indexes. This is why schema and index design influence performance, while still leaving room for the optimizer to choose an efficient route.
Data definition vs data manipulation¶
| SQL family | Purpose | Examples |
|---|---|---|
| DDL | Define structure | CREATE, ALTER, DROP |
| DML | Read and change rows | SELECT, INSERT, UPDATE, DELETE |
| DCL | Control permissions | GRANT, REVOKE |
| TCL | Control transactions | BEGIN, COMMIT, ROLLBACK |
Treat DDL as versioned application code: review it, test it against realistic data, and apply it through migrations. A production schema should not be an unrecorded collection of manual console changes.
Next, learn how keys give rows identity and turn ERD relationships into enforceable references in Keys and Relationships.
Which type is the safer default for an exact monetary amount such as a product price?