How to Design a Database for an E-commerce App:
A Step-by-Step Guide to Building an online store sounds exciting, but behind every smooth checkout button lies a powerful database structure.
As a 2nd-year BCA student currently diving deep into Database Management Systems (DBMS), I realized that textbook theories make a lot more sense when you apply them to real-world applications.
If you are wondering how to design a database for e-commerce, you are in the right place. In this tutorial, we will skip the heavy academic jargon and look at a practical, step-by-step relational database schema design using SQL.
The Core Entities of an E-commerce Database
Before writing code, we need to identify the core components of our system.
For a basic e-commerce application, we need to track four main things:Users: The customers buying products.Products: The items available for sale.Orders: The transactions mapping users to products. Order Items: The specific details (quantity and price) of each item inside an order.Let’s map out the relational database design steps by writing the SQL tables for each entity.
Step 1: writing Relational schema
Creating the Users Table
Every customer needs a unique identifier. We will create a Users table to store basic profile information.
CREATE TABLE Users (
user_id INTEGER PRIMARY KEY AUTOINCREMENT,
full_name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Key Concept: user_id is our Primary Key. It ensures that no two users share the exact same ID, maintaining strict data integrity.
Step 2:
Designing the Products Table.
Next, we need a place to store our inventory. The Products table tracks the name, price, and available stock.
CREATE TABLE Products (
product_id INTEGER PRIMARY KEY AUTOINCREMENT,
product_name TEXT NOT NULL,
price REAL NOT NULL CHECK(price >= 0),
stock_quantity INTEGER NOT NULL DEFAULT 0
);
Key Concept: Notice the CHECK(price >= 0) constraint. This is a crucial DBMS schema design practice that prevents accidental entries of negative prices!
Step 3:
Mapping the Orders Table When a user buys something, we create an order. An order belongs to a specific user, creating a one-to-many relationship (one user can place many orders).
CREATE TABLE Orders (
order_id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER,
order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
total_amount REAL NOT NULL,
FOREIGN KEY (user_id) REFERENCES Users(user_id)
);
Key Concept: user_id here acts as a Foreign Key. It links the Orders table back to the Users table, ensuring you cannot create an order for a user who does not exist.
Step 4:
The Order Items Table (Handling Many-to-Many)
Here is where a common database design trap happens. Can we just put a product_id column inside the Orders table?
No. A customer can buy multiple different products in a single order.To solve this many-to-many relationship, we need a junction table called Order_Items.
CREATE TABLE Order_Items (
order_item_id INTEGER PRIMARY KEY AUTOINCREMENT,
order_id INTEGER,
product_id INTEGER,
quantity INTEGER NOT NULL CHECK(quantity > 0),
price_at_purchase REAL NOT NULL,
FOREIGN KEY (order_id) REFERENCES Orders(order_id),
FOREIGN KEY (product_id) REFERENCES Products(product_id)
);
Why this matters: Storing price_at_purchase is a vital database normalization example. Even if the price of a product changes in the Products table next week, the historical receipt inside Order_Items remains accurate.
Conclusion
Designing a robust database requires thinking about how data changes over time.
By breaking our e-commerce store down into normalized, relational tables, we prevent data duplication and protect transaction history.
If you are learning DBMS like me, try setting this schema up in a lightweight browser environment like SQLite Online or DB-Fiddle to test out your queries!
What project are you currently building to practice your SQL skills? Let me know in the comments below!

Top comments (0)