Skip to main content

🏗️ Lesson 4: Creating Databases & Tables

Time to build something. In this lesson you'll create your first database, define tables with columns, and learn to modify and delete structures — the foundation for everything that follows.

🎯 Learning Objectives

By the end of this lesson, you will be able to:

  • Create and drop databases with CREATE DATABASE and DROP DATABASE
  • Create tables with columns using CREATE TABLE
  • Modify existing tables with ALTER TABLE (add, modify, rename, drop columns)
  • Rename and delete tables with RENAME TABLE and DROP TABLE
  • Use IF EXISTS and IF NOT EXISTS to write safe, repeatable SQL

Estimated Time: 45 minutes

Prerequisites: MySQL running, comfortable with CLI or phpMyAdmin (Lesson 3)

📑 In This Lesson

Creating and Managing Databases

A MySQL server can hold many databases, and each database holds many tables. Think of it like a filing cabinet: the server is the cabinet, each database is a drawer, and each table is a folder inside that drawer.

graph TD A["MySQL Server"] --> B["Database: bookstore"] A --> C["Database: blog"] A --> D["Database: school"] B --> E["Table: books"] B --> F["Table: customers"] B --> G["Table: orders"] C --> H["Table: posts"] C --> I["Table: comments"]

CREATE DATABASE

To create a new database:


CREATE DATABASE bookstore;
                

Output:


Query OK, 1 row affected (0.01 sec)
                    

Verify it exists:


SHOW DATABASES;
                

You should see bookstore in the list alongside the system databases.

CREATE DATABASE IF NOT EXISTS

If you try to create a database that already exists, MySQL throws an error. To avoid this, use the IF NOT EXISTS clause:


-- Safe version — won't error if it already exists
CREATE DATABASE IF NOT EXISTS bookstore;
                

✅ Best Practice

Always use IF NOT EXISTS when creating databases (and tables). It makes your SQL scripts idempotent — safe to run multiple times without errors. This is especially important for setup scripts and deployment.

USE — Switch to Your Database

After creating a database, switch to it:


USE bookstore;
                

Output:


Database changed
                    

Now all CREATE TABLE, SELECT, and other commands will operate inside bookstore.

DROP DATABASE

To permanently delete a database and all its tables and data:


DROP DATABASE bookstore;
                

⚠️ This Is Permanent!

DROP DATABASE immediately and permanently deletes the database and everything in it. There is no confirmation prompt, no undo, and no recycle bin. Always double-check before running this command, especially on a production server.

The safe version:


DROP DATABASE IF EXISTS bookstore;
                

Character Set and Collation

When creating a database, you can specify a character set (which characters can be stored) and collation (how those characters are sorted and compared). The modern default is utf8mb4, which supports all Unicode characters including emoji:


CREATE DATABASE IF NOT EXISTS bookstore
    CHARACTER SET utf8mb4
    COLLATE utf8mb4_unicode_ci;
                

💡 utf8mb4 vs. utf8

MySQL's utf8 is actually a 3-byte subset that can't store emoji or some Asian characters. utf8mb4 is true 4-byte UTF-8. Always use utf8mb4 for new databases — it's been the default since MySQL 8.0.

Naming Conventions

Good names make databases easy to understand and maintain. Here are the conventions used by most professionals:

Rule Good Example Bad Example
Use lowercase for everything customers Customers, CUSTOMERS
Use snake_case for multi-word names order_items orderItems, OrderItems
Table names should be plural nouns books, categories book, category
Column names should be singular and descriptive first_name, email fn, e, data1
Primary keys named id id bookID, pk_book
Foreign keys named referenced_table_id customer_id custID, cust
Avoid reserved words as names order_records order, select, table

📖 Why Lowercase?

Table names are case-sensitive on Linux but case-insensitive on macOS and Windows. Using all lowercase avoids cross-platform bugs. It's also the industry standard for SQL identifiers.

💡 Tip: When in doubt, ask yourself: "If a new developer looked at this name, would they immediately understand what it holds?" If yes, it's a good name.

Creating Tables

The CREATE TABLE statement defines a new table — its name, its columns, and each column's data type. Here's the general syntax:


CREATE TABLE table_name (
    column1  datatype  [constraints],
    column2  datatype  [constraints],
    column3  datatype  [constraints],
    ...
);
                

Let's break this down with a real example:


CREATE TABLE books (
    id          INT AUTO_INCREMENT PRIMARY KEY,
    title       VARCHAR(200) NOT NULL,
    author      VARCHAR(100) NOT NULL,
    price       DECIMAL(8, 2) NOT NULL,
    pages       INT,
    published   DATE,
    in_stock    BOOLEAN DEFAULT TRUE
);
                

Here's what each part means:

Column Type What It Means
id INT AUTO_INCREMENT PRIMARY KEY Integer that auto-generates (1, 2, 3...) and uniquely identifies each row
title VARCHAR(200) NOT NULL Variable-length text up to 200 characters; cannot be empty
author VARCHAR(100) NOT NULL Variable-length text up to 100 characters; cannot be empty
price DECIMAL(8, 2) NOT NULL Exact decimal number with up to 8 digits total and 2 after the decimal point (e.g., 999999.99)
pages INT Integer; allows NULL (we might not know the page count)
published DATE Date value (YYYY-MM-DD format); allows NULL
in_stock BOOLEAN DEFAULT TRUE True/false value; defaults to TRUE if not specified

💡 Data Types Preview

We'll cover data types in full detail in Lesson 5. For now, just know the basics: INT = whole number, VARCHAR(n) = variable-length text, DECIMAL(m,d) = exact decimal, DATE = date, BOOLEAN = true/false.

CREATE TABLE IF NOT EXISTS

Just like databases, you can guard against errors:


CREATE TABLE IF NOT EXISTS books (
    id     INT AUTO_INCREMENT PRIMARY KEY,
    title  VARCHAR(200) NOT NULL,
    author VARCHAR(100) NOT NULL,
    price  DECIMAL(8, 2) NOT NULL
);
                

Understanding the Key Constraints

You saw a few keywords after the data types. Here's a quick reference — we'll explore these deeply in Lesson 5:

Constraint What It Does Example
PRIMARY KEY Uniquely identifies each row; cannot be NULL or duplicated id INT PRIMARY KEY
AUTO_INCREMENT Automatically assigns the next integer (1, 2, 3...) id INT AUTO_INCREMENT
NOT NULL Column cannot contain NULL (empty) values title VARCHAR(200) NOT NULL
DEFAULT Provides a value if none is specified during INSERT in_stock BOOLEAN DEFAULT TRUE
UNIQUE No two rows can have the same value in this column email VARCHAR(100) UNIQUE

Building Our Practice Database

Let's build a database we'll use throughout the rest of this course — an online bookstore. We'll start with three tables and expand them in later lessons.

erDiagram BOOKS { int id PK varchar title varchar author decimal price int pages date published boolean in_stock } CUSTOMERS { int id PK varchar first_name varchar last_name varchar email varchar city date created_at } CATEGORIES { int id PK varchar name varchar description }

📖 Follow Along!

Open your MySQL CLI (mysql -u root -p) and type each command as you read. Building the muscle memory of typing SQL is just as important as understanding the concepts.

Step 1: Create the Database


CREATE DATABASE IF NOT EXISTS bookstore
    CHARACTER SET utf8mb4
    COLLATE utf8mb4_unicode_ci;

USE bookstore;
                

Step 2: Create the Books Table


CREATE TABLE IF NOT EXISTS books (
    id          INT AUTO_INCREMENT PRIMARY KEY,
    title       VARCHAR(200) NOT NULL,
    author      VARCHAR(100) NOT NULL,
    price       DECIMAL(8, 2) NOT NULL,
    pages       INT,
    published   DATE,
    in_stock    BOOLEAN DEFAULT TRUE
);
                

Step 3: Create the Customers Table


CREATE TABLE IF NOT EXISTS customers (
    id          INT AUTO_INCREMENT PRIMARY KEY,
    first_name  VARCHAR(50) NOT NULL,
    last_name   VARCHAR(50) NOT NULL,
    email       VARCHAR(100) NOT NULL UNIQUE,
    city        VARCHAR(50),
    created_at  DATETIME DEFAULT CURRENT_TIMESTAMP
);
                

Notice the new pieces:

  • UNIQUE on email — no two customers can share the same email address
  • DATETIME DEFAULT CURRENT_TIMESTAMP — automatically records when the row was created

Step 4: Create the Categories Table


CREATE TABLE IF NOT EXISTS categories (
    id          INT AUTO_INCREMENT PRIMARY KEY,
    name        VARCHAR(50) NOT NULL UNIQUE,
    description VARCHAR(255)
);
                

Step 5: Verify Your Work


-- List all tables in bookstore
SHOW TABLES;

-- Check each table's structure
DESCRIBE books;
DESCRIBE customers;
DESCRIBE categories;
                

Expected Output for SHOW TABLES:


+---------------------+
| Tables_in_bookstore |
+---------------------+
| books               |
| categories          |
| customers           |
+---------------------+
3 rows in set (0.00 sec)
                    

✅ You Just Built a Database!

Three tables, properly named, with appropriate data types and constraints. This bookstore database will be our playground for the rest of the course. We'll add data in Lesson 6, query it in Lessons 7–10, add relationships in Lessons 11–13, and much more.

Modifying Tables with ALTER TABLE

Requirements change. You'll often need to add new columns, rename existing ones, change data types, or remove columns that are no longer needed. The ALTER TABLE statement handles all of this.

ADD a Column


-- Add a 'phone' column to the customers table
ALTER TABLE customers
ADD COLUMN phone VARCHAR(20);
                

By default, the new column is added at the end. You can control placement:


-- Add 'phone' after the 'email' column
ALTER TABLE customers
ADD COLUMN phone VARCHAR(20) AFTER email;

-- Add a column at the very beginning
ALTER TABLE customers
ADD COLUMN member_id VARCHAR(10) FIRST;
                

MODIFY a Column (change its type or constraints)


-- Make 'phone' longer and require it
ALTER TABLE customers
MODIFY COLUMN phone VARCHAR(30) NOT NULL;
                

⚠️ Be Careful with MODIFY

If the table already has data, changing a column's type can fail or lose data. For example, you can't change a VARCHAR to an INT if the column contains text like "hello". Always check your data first.

RENAME a Column


-- Rename 'phone' to 'phone_number'
ALTER TABLE customers
RENAME COLUMN phone TO phone_number;
                

CHANGE a Column (rename + change type in one step)


-- Rename 'phone_number' to 'mobile' AND change its type
ALTER TABLE customers
CHANGE COLUMN phone_number mobile VARCHAR(25);
                

The difference between RENAME COLUMN and CHANGE COLUMN:

  • RENAME COLUMN — just renames (simpler, MySQL 8.0+)
  • CHANGE COLUMN — renames AND lets you change the data type (works in all versions)

DROP a Column


-- Remove the 'mobile' column entirely
ALTER TABLE customers
DROP COLUMN mobile;
                

⚠️ Dropping Columns Is Permanent

Like DROP DATABASE, this is immediate and irreversible. All data in that column is gone.

Multiple Changes in One Statement

You can combine multiple alterations in a single ALTER TABLE:


ALTER TABLE books
    ADD COLUMN isbn VARCHAR(13) UNIQUE AFTER id,
    ADD COLUMN language VARCHAR(30) DEFAULT 'English',
    MODIFY COLUMN pages INT UNSIGNED;
                

This is more efficient than running three separate ALTER TABLE commands because MySQL only rebuilds the table once.

ALTER TABLE Quick Reference

Operation Syntax
Add a column ALTER TABLE t ADD COLUMN col TYPE;
Add a column at a position ALTER TABLE t ADD COLUMN col TYPE AFTER other_col;
Modify a column's type ALTER TABLE t MODIFY COLUMN col NEW_TYPE;
Rename a column ALTER TABLE t RENAME COLUMN old TO new;
Rename + retype ALTER TABLE t CHANGE COLUMN old new NEW_TYPE;
Drop a column ALTER TABLE t DROP COLUMN col;
Rename the table ALTER TABLE t RENAME TO new_name;

Renaming and Dropping Tables

RENAME TABLE


-- Rename a table
RENAME TABLE categories TO genres;

-- Rename it back
RENAME TABLE genres TO categories;
                

You can also rename multiple tables in a single statement:


RENAME TABLE
    old_name1 TO new_name1,
    old_name2 TO new_name2;
                

DROP TABLE

Permanently deletes a table and all its data:


-- Dangerous — no undo!
DROP TABLE categories;

-- Safer — won't error if the table doesn't exist
DROP TABLE IF EXISTS categories;
                

TRUNCATE TABLE

If you want to keep the table structure but delete all rows, use TRUNCATE:


-- Removes all data but keeps the table
TRUNCATE TABLE books;
                

💡 TRUNCATE vs. DELETE

TRUNCATE TABLE is faster than DELETE FROM table because it doesn't scan rows individually — it drops and recreates the table structure. However, TRUNCATE can't be rolled back in a transaction and resets AUTO_INCREMENT back to 1. Use DELETE when you need fine-grained control; use TRUNCATE when you want to wipe everything quickly.

⚠️ Let's Undo Our Experiments

If you ran any ALTER TABLE or DROP commands on the bookstore tables during this lesson, let's rebuild them cleanly. The easiest way is to drop and recreate:


DROP DATABASE IF EXISTS bookstore;

-- Then re-run the CREATE statements from the
-- "Building Our Practice Database" section above.
                    

We want clean tables for Lesson 5 and beyond.

Inspecting Your Work

After creating or modifying tables, you'll often want to verify the results. Here are the most useful inspection commands:

DESCRIBE — Column Overview


DESCRIBE books;
-- Shorthand:
DESC books;
                

Shows columns, types, nullability, keys, and defaults in a quick table.

SHOW CREATE TABLE — Full Definition


SHOW CREATE TABLE books\G
                

This shows the exact SQL that would recreate the table, including all constraints, defaults, character sets, and engine settings. It's the most complete view of a table's definition:

Output (abbreviated):


*************************** 1. row ***************************
       Table: books
Create Table: CREATE TABLE `books` (
  `id` int NOT NULL AUTO_INCREMENT,
  `title` varchar(200) NOT NULL,
  `author` varchar(100) NOT NULL,
  `price` decimal(8,2) NOT NULL,
  `pages` int DEFAULT NULL,
  `published` date DEFAULT NULL,
  `in_stock` tinyint(1) DEFAULT '1',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
                    

💡 Notice the Differences

MySQL may adjust your definitions slightly: BOOLEAN becomes tinyint(1) (MySQL doesn't have a native boolean type — it uses a tiny integer where 0 = false and 1 = true). DEFAULT TRUE becomes DEFAULT '1'. These are equivalent.

SHOW COLUMNS — Alternative to DESCRIBE


SHOW COLUMNS FROM books;

-- With more detail:
SHOW FULL COLUMNS FROM books;
                

SHOW FULL COLUMNS adds the collation, privileges, and any column comments.

In phpMyAdmin

Click on a table → Structure tab to see the same information visually. The SQL tab with SHOW CREATE TABLE books; works here too.

Exercises

🏋️ Exercise 1: Build the Bookstore

If you haven't already, create the complete bookstore database from scratch. Write a single .sql file that:

  1. Creates the bookstore database (with utf8mb4)
  2. Switches to it with USE
  3. Creates the books table
  4. Creates the customers table
  5. Creates the categories table

Save it as create_bookstore.sql and run it with SOURCE.

✅ Solution

-- create_bookstore.sql
-- Sets up the bookstore database from scratch

CREATE DATABASE IF NOT EXISTS bookstore
    CHARACTER SET utf8mb4
    COLLATE utf8mb4_unicode_ci;

USE bookstore;

CREATE TABLE IF NOT EXISTS books (
    id          INT AUTO_INCREMENT PRIMARY KEY,
    title       VARCHAR(200) NOT NULL,
    author      VARCHAR(100) NOT NULL,
    price       DECIMAL(8, 2) NOT NULL,
    pages       INT,
    published   DATE,
    in_stock    BOOLEAN DEFAULT TRUE
);

CREATE TABLE IF NOT EXISTS customers (
    id          INT AUTO_INCREMENT PRIMARY KEY,
    first_name  VARCHAR(50) NOT NULL,
    last_name   VARCHAR(50) NOT NULL,
    email       VARCHAR(100) NOT NULL UNIQUE,
    city        VARCHAR(50),
    created_at  DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS categories (
    id          INT AUTO_INCREMENT PRIMARY KEY,
    name        VARCHAR(50) NOT NULL UNIQUE,
    description VARCHAR(255)
);
                        

🏋️ Exercise 2: ALTER TABLE Practice

Using ALTER TABLE, make the following changes to the bookstore tables:

  1. Add a rating column to books (DECIMAL(3,2), allows NULL — ratings like 4.75)
  2. Add a phone column to customers after email
  3. Rename the description column in categories to summary
  4. Verify each change with DESCRIBE
  5. Undo all changes so the tables match the original definitions
✅ Solution

-- Make changes
ALTER TABLE books ADD COLUMN rating DECIMAL(3,2);
ALTER TABLE customers ADD COLUMN phone VARCHAR(20) AFTER email;
ALTER TABLE categories RENAME COLUMN description TO summary;

-- Verify
DESCRIBE books;
DESCRIBE customers;
DESCRIBE categories;

-- Undo changes
ALTER TABLE books DROP COLUMN rating;
ALTER TABLE customers DROP COLUMN phone;
ALTER TABLE categories RENAME COLUMN summary TO description;
                        

🏋️ Exercise 3: Design Your Own Table

Inside the bookstore database, create a publishers table with:

  • id — auto-incrementing primary key
  • name — up to 100 characters, required, unique
  • country — up to 50 characters
  • founded_year — integer (e.g., 1925)
  • website — up to 200 characters

After creating it, verify with DESCRIBE and SHOW CREATE TABLE.

✅ Solution

CREATE TABLE IF NOT EXISTS publishers (
    id            INT AUTO_INCREMENT PRIMARY KEY,
    name          VARCHAR(100) NOT NULL UNIQUE,
    country       VARCHAR(50),
    founded_year  INT,
    website       VARCHAR(200)
);

DESCRIBE publishers;
SHOW CREATE TABLE publishers\G
                        

🎯 Quick Quiz

Question 1: What does IF NOT EXISTS do in a CREATE statement?

Question 2: Which command shows the exact SQL used to create a table?

Question 3: What's the difference between DROP TABLE and TRUNCATE TABLE?

Question 4: What's the recommended naming convention for MySQL tables?

Summary

🎉 Key Takeaways

  • CREATE DATABASE creates a new database; USE switches to it
  • CREATE TABLE defines a table with columns, data types, and constraints
  • Always use IF NOT EXISTS / IF EXISTS for safe, repeatable scripts
  • Use utf8mb4 character set for full Unicode support
  • Follow naming conventions: lowercase, snake_case, plural table names
  • ALTER TABLE lets you add, modify, rename, and drop columns on existing tables
  • DROP TABLE removes a table entirely; TRUNCATE TABLE empties data but keeps the structure
  • DESCRIBE gives a quick column overview; SHOW CREATE TABLE shows the full definition
  • The bookstore database with books, customers, and categories tables is our course practice environment

📚 Additional Resources

🚀 What's Next?

You've built the structure — now let's understand the building blocks. In the next lesson, you'll dive deep into data types and constraints — choosing the right type for each column, enforcing rules on your data, and understanding how MySQL stores numbers, text, dates, and more.

🎉 Congratulations!

You've created your first database and tables from scratch. This is the foundation everything else builds on — great work!