Basic Schema Example
Learn database design fundamentals with a simple user-posts schema.
Overview
This example demonstrates:
- Creating basic tables
- Defining columns with constraints
- Setting up primary keys
- Creating foreign key relationships
- Adding sample data
Schema Design
Visual Representation
┌──────────────────┐ ┌──────────────────┐
│ users │ │ posts │
├──────────────────┤ ├──────────────────┤
│ ● id (PK) │────────<│ ● id (PK) │
│ ○ username │ 1:N │ ● user_id (FK) │
│ ○ email │ │ ○ title │
│ ○ created_at │ │ ○ content │
└──────────────────┘ │ ○ published_at │
└──────────────────┘Relationship
- One user can have many posts
- One post belongs to one user
- Cardinality: 1:N (One-to-Many)
Step-by-Step Implementation
Step 1: Create Users Table
- Click "+ Add Table"
- Fill in the form:
Table Name: users
Columns:
┌─────────────┬───────────┬────────┬──────────────────────┐
│ Name │ Type │ Length │ Constraints │
├─────────────┼───────────┼────────┼──────────────────────┤
│ id │ INT │ │ ☑ PK ☑ AI │
│ username │ VARCHAR │ 50 │ ☑ NOT NULL │
│ email │ VARCHAR │ 100 │ ☑ NOT NULL │
│ created_at │ TIMESTAMP │ │ │
└─────────────┴───────────┴────────┴──────────────────────┘- Click "Create Table"
Generated SQL:
sql
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);Step 2: Create Posts Table
- Press Cmd+N (or click Add Table)
- Configure the table:
Table Name: posts
Columns:
┌──────────────┬───────────┬────────┬──────────────────────┐
│ Name │ Type │ Length │ Constraints │
├──────────────┼───────────┼────────┼──────────────────────┤
│ id │ INT │ │ ☑ PK ☑ AI │
│ user_id │ INT │ │ ☑ NOT NULL │
│ title │ VARCHAR │ 200 │ ☑ NOT NULL │
│ content │ TEXT │ │ │
│ published_at │ TIMESTAMP │ │ │
└──────────────┴───────────┴────────┴──────────────────────┘- Click "Create Table"
Generated SQL:
sql
CREATE TABLE posts (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
title VARCHAR(200) NOT NULL,
content TEXT,
published_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);Step 3: Create Relationship
Visual Method:
- Hover over posts.user_id column
- Click the right handle (●)
- Drag to users.id left handle
- Release to create FK
SQL Generated:
sql
ALTER TABLE posts
ADD CONSTRAINT fk_posts_user_id
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE CASCADE
ON UPDATE CASCADE;Step 4: Add Sample Data
Insert Users
- Click on users table
- Click "Browse Data"
- Click "Add Row" and enter:
sql
-- User 1
INSERT INTO users (username, email) VALUES
('johndoe', 'john@example.com');
-- User 2
INSERT INTO users (username, email) VALUES
('janedoe', 'jane@example.com');
-- User 3
INSERT INTO users (username, email) VALUES
('bobsmith', 'bob@example.com');Insert Posts
- Click on posts table
- Click "Browse Data"
- Add posts:
sql
-- Posts by John (user_id = 1)
INSERT INTO posts (user_id, title, content) VALUES
(1, 'My First Post', 'Hello World! This is my first blog post.');
INSERT INTO posts (user_id, title, content) VALUES
(1, 'Learning SQL', 'Today I learned about foreign keys and relationships.');
-- Posts by Jane (user_id = 2)
INSERT INTO posts (user_id, title, content) VALUES
(2, 'Introduction to Databases', 'Databases are essential for modern applications.');
-- Posts by Bob (user_id = 3)
INSERT INTO posts (user_id, title, content) VALUES
(3, 'Why I Love MySQL', 'MySQL is fast, reliable, and easy to use.');Step 5: Query the Data
View all posts with usernames:
sql
SELECT
posts.id,
posts.title,
posts.content,
users.username,
posts.published_at
FROM posts
JOIN users ON posts.user_id = users.id
ORDER BY posts.published_at DESC;Result:
┌────┬──────────────────────────┬─────────────┬─────────────────────┐
│ id │ title │ username │ published_at │
├────┼──────────────────────────┼─────────────┼─────────────────────┤
│ 4 │ Why I Love MySQL │ bobsmith │ 2026-06-26 14:27:00 │
│ 3 │ Introduction to Databases│ janedoe │ 2026-06-26 14:26:45 │
│ 2 │ Learning SQL │ johndoe │ 2026-06-26 14:26:30 │
│ 1 │ My First Post │ johndoe │ 2026-06-26 14:26:15 │
└────┴──────────────────────────┴─────────────┴─────────────────────┘Key Concepts Explained
Primary Key (PK)
sql
id INT AUTO_INCREMENT PRIMARY KEY- Uniquely identifies each row
- Auto-increments for new rows
- Cannot be NULL
- Must be unique
Foreign Key (FK)
sql
user_id INT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id)- Links to another table (users.id)
- Enforces referential integrity
- Prevents orphaned records
- ON DELETE CASCADE: Delete posts when user deleted
NOT NULL Constraint
sql
username VARCHAR(50) NOT NULL- Field is required
- Cannot insert without value
- Ensures data integrity
TIMESTAMP
sql
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP- Automatically set on insert
- Tracks when record was created
- Useful for auditing
Testing the Relationship
View Related Records
- In posts data browser
- Click "Related" button on any post
- See the parent user record
Verify Referential Integrity
Try inserting invalid data:
sql
-- This will FAIL (user_id 999 doesn't exist)
INSERT INTO posts (user_id, title, content) VALUES
(999, 'Invalid Post', 'This will not work');
-- Error: Cannot add or update a child row:
-- a foreign key constraint failsTest CASCADE Delete
sql
-- Delete a user
DELETE FROM users WHERE id = 1;
-- All posts by that user are also deleted (CASCADE)
SELECT * FROM posts WHERE user_id = 1;
-- Returns empty (no orphaned posts)Common Queries
Get all posts by a user
sql
SELECT * FROM posts
WHERE user_id = 1
ORDER BY published_at DESC;Count posts per user
sql
SELECT
users.username,
COUNT(posts.id) as post_count
FROM users
LEFT JOIN posts ON users.id = posts.user_id
GROUP BY users.id, users.username
ORDER BY post_count DESC;Find users with no posts
sql
SELECT users.*
FROM users
LEFT JOIN posts ON users.id = posts.user_id
WHERE posts.id IS NULL;Recent posts with user info
sql
SELECT
posts.title,
posts.content,
users.username,
users.email,
posts.published_at
FROM posts
JOIN users ON posts.user_id = users.id
WHERE posts.published_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
ORDER BY posts.published_at DESC;Best Practices
✅ DO
- Use INT for primary keys
- Always add PRIMARY KEY constraint
- Use AUTO_INCREMENT for IDs
- Add NOT NULL to required fields
- Use meaningful column names (user_id, not uid)
- Add timestamps for auditing
❌ DON'T
- Don't use VARCHAR for IDs
- Don't forget foreign key indexes
- Don't allow NULL in required fields
- Don't use vague names (data, value, info)
- Don't skip referential integrity
Schema Evolution
Add Published Status
sql
ALTER TABLE posts
ADD COLUMN is_published BOOLEAN DEFAULT FALSE;Add View Count
sql
ALTER TABLE posts
ADD COLUMN view_count INT DEFAULT 0;Add User Profile
sql
ALTER TABLE users
ADD COLUMN bio TEXT,
ADD COLUMN avatar_url VARCHAR(255);Extending the Schema
Add Comments Table
posts (1) ────< comments (N)
users (1) ────< comments (N)sql
CREATE TABLE comments (
id INT AUTO_INCREMENT PRIMARY KEY,
post_id INT NOT NULL,
user_id INT NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);Add Categories
categories (1) ────< posts (N)sql
CREATE TABLE categories (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE,
slug VARCHAR(50) NOT NULL UNIQUE
);
ALTER TABLE posts
ADD COLUMN category_id INT,
ADD FOREIGN KEY (category_id) REFERENCES categories(id);Practice Exercises
Exercise 1: Add Likes
Create a table to track post likes:
- User can like multiple posts
- Post can have multiple likes
- No duplicate likes (user + post unique)
Solution
sql
CREATE TABLE post_likes (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
post_id INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE,
UNIQUE KEY unique_like (user_id, post_id)
);Exercise 2: Query Optimization
Add indexes for common queries:
- Posts by user_id
- Posts by published_at
Solution
sql
CREATE INDEX idx_posts_user_id ON posts(user_id);
CREATE INDEX idx_posts_published_at ON posts(published_at);
CREATE INDEX idx_posts_user_published ON posts(user_id, published_at);Next Steps
Learn more advanced patterns: