CREATE TABLE students: We created a new table called "students"
Defined columns: id, name, age, grade
Set data types: INTEGER for numbers, TEXT for strings
Added constraints: PRIMARY KEY, NOT NULL
Tested it: Inserted data to make sure it works!
Real-World Example: Creating a Products Table
CREATE TABLE products (
product_id INTEGER PRIMARY KEY,
product_name TEXT NOT NULL,
price REAL,
stock_quantity INTEGER DEFAULT 0,
category TEXT,
created_date TEXT
);
This creates a table to store product information for an e-commerce store!
Try It: Create a Movies Table
Let's create a table to track your favorite movies:
Output will appear here...
Try It: Create a Tasks/To-Do List Table
Perfect for a task management app:
Output will appear here...
🔍 How CREATE TABLE Works Behind the Scenes
When you run CREATE TABLE, here's what happens:
Database checks if table name exists: If a table with that name already
exists, you'll get an error (unless you use CREATE TABLE IF NOT EXISTS)
Memory allocation: The database reserves space in its catalog to store the
table structure (called metadata)
Schema registration: Column names, data types, and constraints are saved to
the system catalog
Index creation: If you defined a PRIMARY KEY, an index is automatically
created for fast lookups
Ready for data: The table is now ready to receive data via INSERT
statements!
Real-Life Analogy: It's like creating a new file folder:
Check if folder name is available ✓
Create the folder structure ✓
Label all the sections inside ✓
Set up an index tab for quick access ✓
Ready to file documents! ✓
💡 CREATE TABLE IF NOT EXISTS
Use this safer version to avoid errors if the table already exists:
-- Won't error if students table already exists
CREATE TABLE IF NOT EXISTS students (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
-- This pattern is useful in scripts that might run multiple times!
Try It: Using CREATE TABLE IF NOT EXISTS
Output will appear here...
🔤 SQL Data Types
Data types tell SQL what kind of information each column will store.
🎯 Real-Life Analogy: Data Types are Like Container Types
Think about storing different things:
INTEGER (number box): Can only hold whole numbers like 42, -17, 1000
TEXT (string box): Holds any text like "Hello", "abc123"
REAL (decimal box): Holds numbers with decimals like 19.99, 3.14
DATE (calendar box): Holds dates like "2024-01-15"
You wouldn't store apples in a shoe box - same idea with data types!
Common SQLite Data Types:
INTEGER
Whole numbers (no decimals)
age INTEGER
Examples: 42, -17, 1000
REAL
Numbers with decimals
price REAL
Examples: 19.99, 3.14159, -0.5
TEXT
Any text or string
name TEXT
Examples: "Alice", "hello@email.com"
BLOB
Binary data (images, files)
photo BLOB
Examples: Images, PDFs, binary files
NULL
Represents missing/unknown
email TEXT
Meaning: No value provided
Other Database Systems (MySQL, PostgreSQL):
Different databases have more specific types:
VARCHAR(50) - Text with max length of 50 characters
INT - Same as INTEGER
DECIMAL(10,2) - Numbers with fixed decimal places
DATE - Date only (YYYY-MM-DD)
DATETIME - Date and time
BOOLEAN - TRUE or FALSE
Try It: Create Table with Various Data Types
Output will appear here...
🔍 Choosing the Right Data Type:
Ages, IDs, counts: INTEGER
Prices, measurements: REAL or DECIMAL
Names, descriptions: TEXT or VARCHAR
Dates: TEXT (in SQLite) or DATE (in MySQL/PostgreSQL)
True/False flags: INTEGER (0/1) or BOOLEAN
📊 Data Type Decision Guide
Ask yourself these questions:
What are
you storing?
Use this
data type
Example
Whole numbers (no
decimals)
INTEGER
age, quantity, user_id
Numbers with decimals
REAL
price, temperature, rating
Any text or words
TEXT
name, email, description
True/False values
INTEGER (0/1)
is_active, is_verified
Dates and times
TEXT (SQLite)
created_at, birthdate
Files, images, binary data
BLOB
profile_picture, pdf_file
Practice: Choosing the Right Data Types
Try to create a table with appropriate data types for a blog system:
Output will appear here...
⚠️ Common Beginner Mistakes When Creating Tables
Learn from these common pitfalls to avoid frustration!
🎯 Real-Life Analogy: Mistakes are Like Building Code Violations
When building a house, you might make mistakes like:
Forgetting the foundation: No PRIMARY KEY (every table needs one!)
Wrong materials: Using TEXT for numbers you want to calculate with
No building permits: Missing NOT NULL on required fields
Duplicate room names: Creating a table that already exists
These mistakes won't crash your database, but they'll cause problems later!
Mistake #1: Forgetting the PRIMARY KEY
❌ Bad Practice:
CREATE TABLE customers (
name TEXT,
email TEXT
);
-- No way to uniquely identify each customer!
-- What if two people have the same name?
✅ Good Practice:
CREATE TABLE customers (
customer_id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
);
-- Each customer has a unique ID
-- Email is unique and required
Why it matters: Without a PRIMARY KEY, you can't reliably update or delete
specific rows. Two identical rows become impossible to distinguish!
Mistake #2: Using Wrong Data Types
❌ Bad Practice:
CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT,
price TEXT, -- ❌ Price as TEXT!
quantity TEXT -- ❌ Quantity as TEXT!
);
-- Later you try to calculate total:
-- SELECT price * quantity FROM products; -- ERROR!
✅ Good Practice:
CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
price REAL NOT NULL CHECK(price >= 0),
quantity INTEGER NOT NULL CHECK(quantity >= 0)
);
-- Now calculations work!
-- SELECT price * quantity AS total FROM products; -- ✓ Works!
See the Difference:
Output will appear here...
Mistake #3: Forgetting NOT NULL on Required Fields
❌ Bad Practice:
CREATE TABLE users (
id INTEGER PRIMARY KEY,
username TEXT, -- ❌ Could be NULL!
email TEXT -- ❌ Could be NULL!
);
-- Later someone inserts a user with no email:
INSERT INTO users (id, username) VALUES (1, 'john');
-- Now you have a user with NULL email - problematic!
✅ Good Practice:
CREATE TABLE users (
id INTEGER PRIMARY KEY,
username TEXT NOT NULL UNIQUE,
email TEXT NOT NULL UNIQUE
);
-- This prevents incomplete data:
INSERT INTO users (id, username) VALUES (1, 'john'); -- ERROR!
-- Must provide email too!
Mistake #4: Not Using Constraints for Data Validation
❌ Bad Practice:
CREATE TABLE employees (
id INTEGER PRIMARY KEY,
name TEXT,
age INTEGER, -- ❌ No validation!
salary REAL -- ❌ Could be negative!
);
-- Someone could insert invalid data:
INSERT INTO employees VALUES (1, 'Bob', -5, -50000); -- ❌ Nonsense data!
✅ Good Practice:
CREATE TABLE employees (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
age INTEGER CHECK(age >= 18 AND age <= 100),
salary REAL CHECK(salary >= 0)
);
-- Constraints prevent bad data:
INSERT INTO employees VALUES (1, 'Bob', -5, -50000); -- ERROR! Prevented!
Try It: See Constraints in Action
Output will appear here...
Mistake #5: Table Names That Cause Confusion
❌ Bad Practice:
-- Unclear or misleading names:
CREATE TABLE data (id INTEGER, info TEXT); -- Too vague!
CREATE TABLE tbl1 (id INTEGER, val TEXT); -- Meaningless!
CREATE TABLE USER (id INTEGER, name TEXT); -- Reserved keyword!
Be descriptive: Use names that clearly indicate what the table stores
Use underscores: separate_words_like_this (not CamelCase)
Plural vs singular: Be consistent (either "users" or "user", not both)
Avoid reserved keywords: Don't use names like USER, SELECT, TABLE, etc.
Keep it simple: Shorter is better, but clarity comes first
🔍 Quick Checklist Before Creating a Table:
Ask yourself these questions:
✓ Does my table have a PRIMARY KEY?
✓ Are my data types appropriate for the data I'm storing?
✓ Did I add NOT NULL to required fields?
✓ Do I have UNIQUE constraints where needed (emails, usernames)?
✓ Did I add CHECK constraints for data validation?
✓ Is my table name clear and descriptive?
✓ Did I avoid using reserved SQL keywords as table/column names?
If you can answer "yes" to all of these, you're on the right track!
⚡ Constraints - Rules for Your Data
Constraints enforce rules to keep your data clean and consistent!
🎯 Real-Life Analogy: Constraints are Like Form Validation
When filling out an online form:
NOT NULL: "This field is required" (can't be empty)
UNIQUE: "Email already in use" (must be unique)
DEFAULT: Country field pre-filled with "USA"
CHECK: "Age must be 18 or older" (validation rule)
Constraints prevent bad data from entering your database!
Common Constraints:
PRIMARY KEY
Unique identifier for each row
id INTEGER PRIMARY KEY
Automatically NOT NULL and UNIQUE
NOT NULL
Column must have a value
name TEXT NOT NULL
Prevents empty/missing data
UNIQUE
No duplicate values allowed
email TEXT UNIQUE
Ensures uniqueness (like usernames)
DEFAULT
Sets a default value
status TEXT DEFAULT 'active'
Uses default if nothing provided
CHECK
Custom validation rule
age INTEGER CHECK(age >= 18)
Enforces business logic
FOREIGN KEY
Links to another table
dept_id INTEGER REFERENCES departments(id)
Maintains relationships
Try It: Create Table with Multiple Constraints
Output will appear here...
Try It: See Constraints in Action (This Will Fail!)
Watch how constraints prevent bad data:
Output will appear here...
You should see an error - constraints are working to protect your data!
🔍 Why Use Constraints?
Data Integrity: Prevents invalid data from entering the database
Consistency: Ensures all data follows the same rules
Error Prevention: Catches mistakes before they become problems
Documentation: Constraints describe business rules in the database itself
Troubleshooting Common Constraint Errors
Error 1: "NOT NULL constraint failed"
What it means: You tried to insert a row without providing a value for a NOT
NULL column
-- This will fail:
INSERT INTO users (id, username) VALUES (1, 'alice');
-- Error: NOT NULL constraint failed: users.email
-- Solution: Provide all required fields
INSERT INTO users (id, username, email) VALUES (1, 'alice', 'alice@email.com');
Error 2: "UNIQUE constraint failed"
What it means: You tried to insert a value that already exists in a UNIQUE
column
-- First insert succeeds:
INSERT INTO users (id, username, email) VALUES (1, 'alice', 'alice@email.com');
-- This will fail (duplicate email):
INSERT INTO users (id, username, email) VALUES (2, 'bob', 'alice@email.com');
-- Error: UNIQUE constraint failed: users.email
-- Solution: Use a different, unique value
INSERT INTO users (id, username, email) VALUES (2, 'bob', 'bob@email.com');
Error 3: "CHECK constraint failed"
What it means: The value you're trying to insert doesn't meet the CHECK
condition
CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT,
price REAL CHECK(price >= 0)
);
-- This will fail:
INSERT INTO products VALUES (1, 'Laptop', -100);
-- Error: CHECK constraint failed: products
-- Solution: Provide a valid value
INSERT INTO products VALUES (1, 'Laptop', 999.99);
Error 4: "FOREIGN KEY constraint failed"
What it means: You're trying to insert a foreign key value that doesn't exist in
the referenced table
-- Try to create an order for customer_id=999 (doesn't exist):
INSERT INTO orders (order_id, customer_id) VALUES (1, 999);
-- Error: FOREIGN KEY constraint failed
-- Solution: First create the customer, OR use an existing customer_id
INSERT INTO customers (customer_id, name) VALUES (999, 'New Customer');
INSERT INTO orders (order_id, customer_id) VALUES (1, 999); -- Now works!
💡 Constraint Error Quick Fix Guide:
Error
Message
What You
Forgot
How to
Fix
NOT NULL constraint failed
Required field missing
Provide value for all NOT
NULL columns
UNIQUE constraint failed
Value already exists
Use a different unique
value
CHECK constraint failed
Value violates rules
Check the CHECK condition
and provide valid value
FOREIGN KEY constraint
failed
Referenced record doesn't
exist
Create the referenced
record first
Practice: Fix the Constraint Errors
Each statement below has an error. Uncomment them one by one and see what happens:
Output will appear here...
🔑 Primary Keys Explained
Every table needs a unique identifier - that's the primary key!
🎯 Real-Life Analogy: Primary Keys are Like Student ID Numbers
Need to change a table structure after it's created? Use ALTER TABLE!
🎯 Real-Life Analogy: ALTER TABLE is Like Renovating a Building
Your house (table) is already built, but you want to:
Add a new room: ALTER TABLE ADD COLUMN
Remove a room: ALTER TABLE DROP COLUMN
Rename the house: ALTER TABLE RENAME TO
Remodel a room: ALTER TABLE MODIFY COLUMN
ALTER lets you modify without tearing down and rebuilding!
1. Adding New Columns:
Try It: Add Column to Existing Table
Output will appear here...
ALTER TABLE ADD COLUMN Syntax:
ALTER TABLE table_name
ADD COLUMN column_name data_type constraints;
Note: Existing rows will have NULL for the new column (unless you specify
DEFAULT)
2. Renaming Tables:
Try It: Rename a Table
Output will appear here...
🔍 SQLite ALTER Limitations:
SQLite has limited ALTER capabilities compared to other databases:
✅ Can: ADD COLUMN
✅ Can: RENAME TABLE
✅ Can: RENAME COLUMN (SQLite 3.25+)
❌ Cannot: DROP COLUMN (need workaround)
❌ Cannot: MODIFY COLUMN (need workaround)
❌ Cannot: Add/Remove constraints on existing columns
MySQL and PostgreSQL support more ALTER operations!
Workaround: Recreating Table to Remove Column
-- Steps to remove a column in SQLite:
-- 1. Create new table without the unwanted column
CREATE TABLE employees_new (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
-- removed 'age' column
);
-- 2. Copy data from old table
INSERT INTO employees_new SELECT id, name FROM employees_old;
-- 3. Drop old table
DROP TABLE employees_old;
-- 4. Rename new table
ALTER TABLE employees_new RENAME TO employees_old;
🗑️ DROP TABLE - Deleting Tables
Need to completely remove a table? Use DROP TABLE (but be careful!)
⚠️ Warning: DROP TABLE is Permanent!
Think of DROP TABLE like demolishing a building:
The table structure is completely deleted
All data inside is permanently lost
There's NO UNDO button!
Always backup your data before using DROP TABLE!
DROP TABLE Syntax:
DROP TABLE table_name;
-- Safer version (won't error if table doesn't exist):
DROP TABLE IF EXISTS table_name;
Try It: Create and Drop a Test Table
Output will appear here...
Safe Dropping Pattern:
-- Check if table exists before dropping
DROP TABLE IF EXISTS old_data;
-- Create fresh table
CREATE TABLE new_data (
id INTEGER PRIMARY KEY,
info TEXT
);
-- This won't error even if old_data didn't exist
🏗️ Schema Design Basics
Learn to design good database structures - the foundation of great applications!
🎯 What is a Schema?
A database schema is the blueprint of your database - the overall structure of
tables, columns, relationships, and constraints.
Think of it like architectural plans for a house:
Tables: Rooms in the house
Columns: Features of each room
Relationships: How rooms connect (hallways, doors)
Constraints: Building codes and rules
Good Schema Design Principles:
1. Normalization
Avoid data duplication
Store each piece of info once
2. Meaningful Names
Use clear table/column names
users, products, order_items
3. Primary Keys
Every table needs a unique ID
Use INTEGER AUTOINCREMENT
4. Right Data Types
Choose appropriate types
INTEGER for counts, REAL for prices
5. Constraints
Enforce data integrity
NOT NULL, UNIQUE, CHECK
6. Documentation
Add comments explaining tables
Make intent clear
Example: Well-Designed E-Commerce Schema
-- Customers table
CREATE TABLE customers (
customer_id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT NOT NULL UNIQUE,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);
-- Products table
CREATE TABLE products (
product_id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
description TEXT,
price REAL NOT NULL CHECK(price >= 0),
stock_quantity INTEGER DEFAULT 0
);
-- Orders table
CREATE TABLE orders (
order_id INTEGER PRIMARY KEY AUTOINCREMENT,
customer_id INTEGER NOT NULL,
order_date TEXT DEFAULT CURRENT_TIMESTAMP,
total_amount REAL,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
-- Order Items (junction table for many-to-many)
CREATE TABLE order_items (
order_id INTEGER,
product_id INTEGER,
quantity INTEGER NOT NULL CHECK(quantity > 0),
price_at_purchase REAL NOT NULL,
PRIMARY KEY (order_id, product_id),
FOREIGN KEY (order_id) REFERENCES orders(order_id),
FOREIGN KEY (product_id) REFERENCES products(product_id)
);
🔍 Why This Design is Good:
No duplication: Customer info stored once, not repeated in every order
Clear relationships: Foreign keys link tables properly
Data integrity: Constraints prevent invalid data (negative prices, empty
names)
Scalable: Can add new products/customers without redesigning
Normalization is the process of organizing data to reduce redundancy and improve
data integrity.
Real-Life Analogy: Imagine organizing your kitchen:
Before (not normalized): You keep salt, pepper, and spices scattered
everywhere - in every cabinet, drawer, and countertop. Lots of duplication!
After (normalized): You have ONE spice rack where all spices are stored. No
duplication, easy to find, easy to update!
Same idea with databases - store each piece of information in ONE place!
❌ Bad Design: Not Normalized (Data Duplication)
Problem: Customer information repeated in every order!
CREATE TABLE orders_bad (
order_id INTEGER PRIMARY KEY,
customer_name TEXT,
customer_email TEXT,
customer_address TEXT,
product_name TEXT,
product_price REAL,
quantity INTEGER
);
-- Sample data showing duplication:
-- Order 1: John Doe, john@email.com, 123 Main St, Laptop, 999.99, 1
-- Order 2: John Doe, john@email.com, 123 Main St, Mouse, 29.99, 2
-- Order 3: John Doe, john@email.com, 123 Main St, Keyboard, 79.99, 1
-- Problems:
-- 1. John's info repeated 3 times (waste of space!)
-- 2. If John changes email, must update 3 rows (error-prone!)
-- 3. Misspelling John's name in one order causes inconsistency
✅ Good Design: Normalized (No Duplication)
Solution: Separate tables with relationships!
-- Customer info stored ONCE
CREATE TABLE customers_normalized (
customer_id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
address TEXT
);
-- Product info stored ONCE
CREATE TABLE products_normalized (
product_id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
price REAL NOT NULL
);
-- Orders only store IDs (references to other tables)
CREATE TABLE orders_normalized (
order_id INTEGER PRIMARY KEY,
customer_id INTEGER,
product_id INTEGER,
quantity INTEGER,
FOREIGN KEY (customer_id) REFERENCES customers_normalized(customer_id),
FOREIGN KEY (product_id) REFERENCES products_normalized(product_id)
);
-- Benefits:
-- 1. Customer info stored ONCE - no duplication!
-- 2. Update John's email in ONE place - affects all orders automatically!
-- 3. Consistent data - can't have typos in repeated data!
Try It: See Normalization Benefits
Output will appear here...
Bad vs Good Design: More Examples
Example 1: Student Enrollment System
❌ Bad Design (Denormalized):
CREATE TABLE enrollments_bad (
enrollment_id INTEGER PRIMARY KEY,
student_name TEXT,
student_email TEXT,
student_major TEXT,
course_name TEXT,
course_instructor TEXT,
course_credits INTEGER
);
-- If student takes 5 courses, their info is repeated 5 times!
-- If instructor name changes, must update many rows!
✅ Good Design (Normalized):
CREATE TABLE students (
student_id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
major TEXT
);
CREATE TABLE courses (
course_id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
instructor TEXT NOT NULL,
credits INTEGER
);
CREATE TABLE enrollments_good (
enrollment_id INTEGER PRIMARY KEY,
student_id INTEGER,
course_id INTEGER,
grade TEXT,
FOREIGN KEY (student_id) REFERENCES students(student_id),
FOREIGN KEY (course_id) REFERENCES courses(course_id)
);
-- Student info stored once, course info stored once!
-- Enrollments just link them together
Example 2: Library System
❌ Bad Design:
CREATE TABLE checkouts_bad (
checkout_id INTEGER PRIMARY KEY,
member_name TEXT,
member_phone TEXT,
book_title TEXT,
book_author TEXT,
book_isbn TEXT,
checkout_date TEXT,
due_date TEXT
);
-- Book details repeated every time someone checks it out!
-- Member info repeated for every book they borrow!
✅ Good Design:
CREATE TABLE members (
member_id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
phone TEXT,
email TEXT UNIQUE
);
CREATE TABLE books (
book_id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
author TEXT NOT NULL,
isbn TEXT UNIQUE
);
CREATE TABLE checkouts_good (
checkout_id INTEGER PRIMARY KEY AUTOINCREMENT,
member_id INTEGER NOT NULL,
book_id INTEGER NOT NULL,
checkout_date TEXT DEFAULT CURRENT_TIMESTAMP,
due_date TEXT NOT NULL,
return_date TEXT,
FOREIGN KEY (member_id) REFERENCES members(member_id),
FOREIGN KEY (book_id) REFERENCES books(book_id)
);
-- Clean, organized, no duplication!
🎓 The 3 Normal Forms (Simplified)
First Normal Form (1NF): No repeating groups - each cell has only ONE value
❌ Bad: phone_numbers = "555-1234, 555-5678, 555-9012" (multiple values in one cell)
✅ Good: Create separate rows or a phone_numbers table
Second Normal Form (2NF): No partial dependencies - all columns depend on the
entire primary key
❌ Bad: In order_items(order_id, product_id, customer_name) - customer_name only depends on
order_id, not product_id
✅ Good: Move customer_name to orders table
Third Normal Form (3NF): No transitive dependencies - no column depends on
another non-key column
❌ Bad: employees(id, department_id, department_name) - department_name depends on
department_id, not id
✅ Good: Create separate departments table
Simple Rule: Each table should be about ONE thing, and store that thing's info
ONCE!
Practice: Design a Normalized Schema
Try creating a normalized schema for a movie rental system:
Output will appear here...
🔍 Schema Design Checklist:
Before finalizing your database schema, ask yourself:
✓ Is each table about ONE thing? (customers, products, orders - not all
mixed together)
✓ Is data stored only ONCE? (no repeating customer names in every order)
✓ Do all tables have PRIMARY KEYS?
✓ Are relationships properly defined with FOREIGN KEYS?
✓ Are data types appropriate? (INTEGER for IDs, REAL for prices)
✓ Are constraints in place? (NOT NULL, UNIQUE, CHECK)
✓ Are table and column names clear and consistent?
✓ Can the schema handle future growth? (adding new products/users without
redesign)
Practice Exercises
Part 1: Guided Exercises
Guided Exercise 1: Create a Library Table
Task: Create a table called "library_books" with columns for: id (primary key),
title (required), author (required), isbn (unique), year_published (integer), available (default
1 for true).
NOT NULL: Ensures title and author are always provided
UNIQUE: No duplicate ISBN numbers
DEFAULT 1: Books are available by default
Part 2: Independent Practice
Guided Exercise 2: Create a Products Table
Task: Create a table for an online store with: product_id (PK, autoinc), name
(required), category (required), price (real, must be > 0), stock (integer, default 0),
is_available (default 1).
Output will appear here...
Explanation:
CHECK(price > 0): Ensures no free or negative priced products
DEFAULT 0 for stock: New products start with 0 stock
is_available flag: Track if product is currently sellable
Guided Exercise 3: Add a Column to Existing Table
Task: Add a "phone" column to the library_books table you created earlier.
Output will appear here...
Explanation:
ALTER TABLE ADD COLUMN: Adds new column without losing existing data
Existing rows get NULL: Unless you specify DEFAULT value
language DEFAULT 'English': All existing books automatically get 'English'
Guided Exercise 4: Design a Normalized Schema
Task: Create a simple normalized schema for a school with students, classes, and
enrollments.
Output will appear here...
Explanation:
students_school: Stores student info ONCE
classes_school: Stores class info ONCE
enrollments_school: Junction table links students to classes (many-to-many)
FOREIGN KEYS: Ensure data integrity - can't enroll non-existent student
JOIN query: Combines all three tables to show complete enrollment info
Part 2: Independent Practice
Challenge 1: Employee Management System
Difficulty: Medium
Task: Create an "employees_new" table with: emp_id (PK, autoinc), full_name
(required), email (required, unique), hire_date (text), salary (real, must be >= 0), is_active
(default 1).
Output will appear here...
CREATE TABLE employees_new (
emp_id INTEGER PRIMARY KEY AUTOINCREMENT,
full_name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
hire_date TEXT,
salary REAL CHECK(salary >= 0),
is_active INTEGER DEFAULT 1
);
-- Test it:
INSERT INTO employees_new (full_name, email, hire_date, salary)
VALUES ('John Doe', 'john@company.com', '2024-01-15', 75000);
SELECT * FROM employees_new;
Challenge 2: Blog Platform
Difficulty: Medium
Task: Design a normalized schema for a blog with: authors table (author_id,
name, email, bio), posts table (post_id, author_id, title, content, published_date, view_count).
Include proper constraints and foreign keys.
Output will appear here...
CREATE TABLE authors (
author_id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
bio TEXT
);
CREATE TABLE posts (
post_id INTEGER PRIMARY KEY AUTOINCREMENT,
author_id INTEGER NOT NULL,
title TEXT NOT NULL,
content TEXT NOT NULL,
published_date TEXT DEFAULT CURRENT_TIMESTAMP,
view_count INTEGER DEFAULT 0,
FOREIGN KEY (author_id) REFERENCES authors(author_id)
);
-- Test it:
INSERT INTO authors (name, email, bio) VALUES ('Jane Doe', 'jane@blog.com', 'Tech writer');
INSERT INTO posts (author_id, title, content) VALUES (1, 'My First Post', 'Hello World!');
SELECT p.title, a.name AS author, p.published_date
FROM posts p
JOIN authors a ON p.author_id = a.author_id;
Challenge 3: Music Streaming Service
Difficulty: Hard
Task: Create a complete schema for a music streaming service with: artists
(artist_id, name, country), albums (album_id, artist_id, title, release_year), songs (song_id,
album_id, title, duration_seconds), playlists (playlist_id, user_id, name), playlist_songs
(junction table). Include all necessary constraints.
Output will appear here...
CREATE TABLE artists (
artist_id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
country TEXT
);
CREATE TABLE albums (
album_id INTEGER PRIMARY KEY AUTOINCREMENT,
artist_id INTEGER NOT NULL,
title TEXT NOT NULL,
release_year INTEGER,
FOREIGN KEY (artist_id) REFERENCES artists(artist_id)
);
CREATE TABLE songs (
song_id INTEGER PRIMARY KEY AUTOINCREMENT,
album_id INTEGER NOT NULL,
title TEXT NOT NULL,
duration_seconds INTEGER CHECK(duration_seconds > 0),
FOREIGN KEY (album_id) REFERENCES albums(album_id)
);
CREATE TABLE users_music (
user_id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
email TEXT UNIQUE NOT NULL
);
CREATE TABLE playlists (
playlist_id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
name TEXT NOT NULL,
created_date TEXT DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users_music(user_id)
);
CREATE TABLE playlist_songs (
playlist_id INTEGER,
song_id INTEGER,
added_date TEXT DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (playlist_id, song_id),
FOREIGN KEY (playlist_id) REFERENCES playlists(playlist_id),
FOREIGN KEY (song_id) REFERENCES songs(song_id)
);
Challenge 4: Restaurant Reservation System
Difficulty: Medium
Task: Create tables for: customers (customer_id, name, phone, email), tables
(table_id, table_number, capacity), reservations (reservation_id, customer_id, table_id,
reservation_date, party_size, status). Status must be one of: 'Pending', 'Confirmed',
'Completed', 'Cancelled'.
Output will appear here...
CREATE TABLE customers_restaurant (
customer_id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
phone TEXT,
email TEXT UNIQUE
);
CREATE TABLE tables_restaurant (
table_id INTEGER PRIMARY KEY AUTOINCREMENT,
table_number INTEGER UNIQUE NOT NULL,
capacity INTEGER NOT NULL CHECK(capacity > 0)
);
CREATE TABLE reservations (
reservation_id INTEGER PRIMARY KEY AUTOINCREMENT,
customer_id INTEGER NOT NULL,
table_id INTEGER NOT NULL,
reservation_date TEXT NOT NULL,
party_size INTEGER NOT NULL CHECK(party_size > 0),
status TEXT DEFAULT 'Pending' CHECK(status IN ('Pending', 'Confirmed', 'Completed', 'Cancelled')),
FOREIGN KEY (customer_id) REFERENCES customers_restaurant(customer_id),
FOREIGN KEY (table_id) REFERENCES tables_restaurant(table_id)
);
-- Test it:
INSERT INTO customers_restaurant (name, phone, email) VALUES ('Alice Johnson', '555-1234', 'alice@email.com');
INSERT INTO tables_restaurant (table_number, capacity) VALUES (1, 4);
INSERT INTO reservations (customer_id, table_id, reservation_date, party_size, status)
VALUES (1, 1, '2024-12-25 19:00', 4, 'Confirmed');
SELECT * FROM reservations;
Challenge 5: E-Learning Platform
Difficulty: Hard
Task: Design a complete schema for an e-learning platform with: instructors,
courses (linked to instructors), lessons (linked to courses), students, and enrollments
(students enrolled in courses with progress tracking). Include constraints for: course price >=
0, lesson order numbers, enrollment date defaults.
Output will appear here...
CREATE TABLE instructors (
instructor_id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
bio TEXT
);
CREATE TABLE courses (
course_id INTEGER PRIMARY KEY AUTOINCREMENT,
instructor_id INTEGER NOT NULL,
title TEXT NOT NULL,
description TEXT,
price REAL DEFAULT 0 CHECK(price >= 0),
created_date TEXT DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (instructor_id) REFERENCES instructors(instructor_id)
);
CREATE TABLE lessons (
lesson_id INTEGER PRIMARY KEY AUTOINCREMENT,
course_id INTEGER NOT NULL,
title TEXT NOT NULL,
content TEXT,
lesson_order INTEGER NOT NULL,
duration_minutes INTEGER,
FOREIGN KEY (course_id) REFERENCES courses(course_id)
);
CREATE TABLE students (
student_id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
join_date TEXT DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE course_enrollments (
enrollment_id INTEGER PRIMARY KEY AUTOINCREMENT,
student_id INTEGER NOT NULL,
course_id INTEGER NOT NULL,
enrollment_date TEXT DEFAULT CURRENT_TIMESTAMP,
progress_percent INTEGER DEFAULT 0 CHECK(progress_percent >= 0 AND progress_percent <= 100),
completed INTEGER DEFAULT 0,
FOREIGN KEY (student_id) REFERENCES students(student_id),
FOREIGN KEY (course_id) REFERENCES courses(course_id)
);
📝 Knowledge Check Quiz
1. Which constraint ensures a column cannot be empty?
2. What data type should you use for prices like
$19.99?
3. What does AUTOINCREMENT do?
4. What does the DEFAULT constraint do?
5. Which command adds a new column to an existing
table?