Skip to main content
SQL PROJECT TAKEN FROM CHATGPT SEPTEMBER 2026
Below is one polished, blog-ready SQL project. I’ve removed the interview-focused material and kept the explanation practical and beginner-friendly.
SQL Data Analytics Project: E-Commerce Sales Analysis
Introduction
SQL is one of the most important tools for analyzing business data. In this project, we will build a simple E-Commerce Sales Analysis project using SQL.
The goal is to analyze customer orders and answer important business questions such as:
How much revenue did the business generate?
Which products are selling the most?
Who are the top customers?
What are the monthly sales trends?
What is the average order value?
Which categories generate the most revenue?
How can SQL queries be optimized for large datasets?
This project is suitable for beginners who want to learn SQL through a practical data analytics example.
1. Project Objective
Imagine that we work with an online shopping company.
The company stores information about:
Customers
Products
Orders
Order details
Product categories
Management wants to understand sales performance and customer behavior.
We will use SQL to transform this raw data into useful business information.
2. Database Structure
We will create four tables:
Customers
|
| customer_id
↓
Orders
|
| order_id
↓
Order_Items
|
| product_id
↓
Products
The tables are:
customers
orders
products
order_items
3. Create the Customers Table
CREATE TABLE customers (
customer_id INT PRIMARY KEY,
customer_name VARCHAR(100),
city VARCHAR(50),
signup_date DATE
);
The table contains basic customer information.
Example:
customer_id customer_name city signup_date
1 Rahul Sharma Delhi 2025-01-10
2 Priya Singh Mumbai 2025-02-15
3 Amit Kumar Bangalore 2025-03-20
4. Create the Products Table
CREATE TABLE products (
product_id INT PRIMARY KEY,
product_name VARCHAR(100),
category VARCHAR(50),
price DECIMAL(10,2)
);
Example data:
product_id product_name category price
101 Laptop Electronics 60000
102 Mouse Electronics 800
103 Keyboard Electronics 1500
104 Shoes Fashion 2500
105 T-Shirt Fashion 1200
5. Create the Orders Table
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
order_date DATE,
status VARCHAR(30),
FOREIGN KEY (customer_id)
REFERENCES customers(customer_id)
);
Example:
order_id customer_id order_date status
1001 1 2026-01-05 Completed
1002 2 2026-01-10 Completed
1003 1 2026-02-15 Completed
1004 3 2026-02-20 Cancelled
6. Create the Order Items Table
An order can contain multiple products, so we create a separate table.
CREATE TABLE order_items (
order_item_id INT PRIMARY KEY,
order_id INT,
product_id INT,
quantity INT,
FOREIGN KEY (order_id)
REFERENCES orders(order_id),
FOREIGN KEY (product_id)
REFERENCES products(product_id)
);
Example:
order_item_id order_id product_id quantity
1 1001 101 1
2 1001 102 2
3 1002 104 1
4 1003 103 2
7. Project Question 1: How Many Customers Do We Have?
SELECT COUNT(*) AS total_customers
FROM customers;
COUNT() counts the number of records.
This query gives us the total number of registered customers.
8. Project Question 2: How Many Orders Were Placed?
SELECT COUNT(*) AS total_orders
FROM orders;
This gives the total number of orders in the database.
If cancelled orders should not be included:
SELECT COUNT(*) AS completed_orders
FROM orders
WHERE status = 'Completed';
This is more useful when calculating actual business performance.
9. Project Question 3: Calculate Total Revenue
Revenue can be calculated using:
Quantity × Product Price
SQL:
SELECT
SUM(oi.quantity * p.price) AS total_revenue
FROM order_items oi
JOIN products p
ON oi.product_id = p.product_id
JOIN orders o
ON oi.order_id = o.order_id
WHERE o.status = 'Completed';
Here we combine three tables:
order_items
↓
products
↓
orders
The query calculates revenue only from completed orders.
10. Project Question 4: Find the Top 5 Products
SELECT
p.product_name,
SUM(oi.quantity) AS total_quantity_sold
FROM order_items oi
JOIN products p
ON oi.product_id = p.product_id
JOIN orders o
ON oi.order_id = o.order_id
WHERE o.status = 'Completed'
GROUP BY p.product_name
ORDER BY total_quantity_sold DESC
LIMIT 5;
The query:
Joins products and orders.
Removes cancelled orders.
Calculates total quantity sold.
Groups products.
Sorts them from highest to lowest.
Returns the top five.
11. Project Question 5: Find Revenue by Product
SELECT
p.product_name,
SUM(oi.quantity * p.price) AS revenue
FROM order_items oi
JOIN products p
ON oi.product_id = p.product_id
JOIN orders o
ON oi.order_id = o.order_id
WHERE o.status = 'Completed'
GROUP BY p.product_name
ORDER BY revenue DESC;
This helps the business understand which products generate the most money.
A product with high sales quantity is not always the product with the highest revenue.
For example:
Mouse
100 units × ₹800 = ₹80,000
Laptop
2 units × ₹60,000 = ₹120,000
The laptop sells fewer units but generates more revenue.
12. Project Question 6: Find the Top 5 Customers
SELECT
c.customer_id,
c.customer_name,
SUM(oi.quantity * p.price) AS total_spent
FROM customers c
JOIN orders o
ON c.customer_id = o.customer_id
JOIN order_items oi
ON o.order_id = oi.order_id
JOIN products p
ON oi.product_id = p.product_id
WHERE o.status = 'Completed'
GROUP BY
c.customer_id,
c.customer_name
ORDER BY total_spent DESC
LIMIT 5;
This identifies the customers who contribute the most revenue.
The company can use this information to understand its most valuable customers.
13. Project Question 7: Calculate Average Order Value
Average Order Value, or AOV, tells us the average amount spent per order.
SELECT
AVG(order_total) AS average_order_value
FROM (
SELECT
o.order_id,
SUM(oi.quantity * p.price) AS order_total
FROM orders o
JOIN order_items oi
ON o.order_id = oi.order_id
JOIN products p
ON oi.product_id = p.product_id
WHERE o.status = 'Completed'
GROUP BY o.order_id
) AS order_totals;
The calculation works in two steps.
First:
Calculate the value of every order
Then:
Calculate the average of those order values
14. Project Question 8: Monthly Revenue
Monthly revenue is one of the most useful metrics in sales analytics.
For PostgreSQL:
SELECT
DATE_TRUNC('month', o.order_date) AS month,
SUM(oi.quantity * p.price) AS revenue
FROM orders o
JOIN order_items oi
ON o.order_id = oi.order_id
JOIN products p
ON oi.product_id = p.product_id
WHERE o.status = 'Completed'
GROUP BY DATE_TRUNC('month', o.order_date)
ORDER BY month;
The result might look like:
Month Revenue
January ₹150,000
February ₹185,000
March ₹220,000
This allows the company to identify growth or declining sales.
15. Project Question 9: Revenue by Category
SELECT
p.category,
SUM(oi.quantity * p.price) AS revenue
FROM order_items oi
JOIN products p
ON oi.product_id = p.product_id
JOIN orders o
ON oi.order_id = o.order_id
WHERE o.status = 'Completed'
GROUP BY p.category
ORDER BY revenue DESC;
Example result:
Category Revenue
Electronics ₹500,000
Fashion ₹300,000
Home ₹180,000
This helps management understand which product categories are performing best.
16. Project Question 10: Find Customers Who Never Ordered
This is an important example of a LEFT JOIN.
SELECT
c.customer_id,
c.customer_name
FROM customers c
LEFT JOIN orders o
ON c.customer_id = o.customer_id
WHERE o.order_id IS NULL;
Why use LEFT JOIN?
Because we want to keep all customers, including customers who don't have an order.
The result identifies customers who registered but never purchased anything.
17. Project Question 11: Find Cancelled Orders
SELECT
order_id,
customer_id,
order_date
FROM orders
WHERE status = 'Cancelled';
This can help the business investigate why orders are being cancelled.
18. Project Question 12: Find the Highest-Value Order
SELECT
o.order_id,
SUM(oi.quantity * p.price) AS order_value
FROM orders o
JOIN order_items oi
ON o.order_id = oi.order_id
JOIN products p
ON oi.product_id = p.product_id
WHERE o.status = 'Completed'
GROUP BY o.order_id
ORDER BY order_value DESC
LIMIT 1;
This identifies the largest completed order.
19. Using CASE WHEN for Sales Classification
We can classify customers based on their spending.
SELECT
c.customer_id,
c.customer_name,
SUM(oi.quantity * p.price) AS total_spent,
CASE
WHEN SUM(oi.quantity * p.price) >= 100000
THEN 'High Value'
WHEN SUM(oi.quantity * p.price) >= 50000
THEN 'Medium Value'
ELSE 'Low Value'
END AS customer_segment
FROM customers c
JOIN orders o
ON c.customer_id = o.customer_id
JOIN order_items oi
ON o.order_id = oi.order_id
JOIN products p
ON oi.product_id = p.product_id
WHERE o.status = 'Completed'
GROUP BY
c.customer_id,
c.customer_name;
Now every customer receives a segment:
High Value
Medium Value
Low Value
This is useful for customer segmentation.
20. Finding the Top Product in Each Category
Window functions can solve more advanced analytical problems.
WITH product_sales AS (
SELECT
p.category,
p.product_name,
SUM(oi.quantity * p.price) AS revenue
FROM products p
JOIN order_items oi
ON p.product_id = oi.product_id
JOIN orders o
ON oi.order_id = o.order_id
WHERE o.status = 'Completed'
GROUP BY
p.category,
p.product_name
),
ranked_products AS (
SELECT
*,
RANK() OVER (
PARTITION BY category
ORDER BY revenue DESC
) AS product_rank
FROM product_sales
)
SELECT
category,
product_name,
revenue
FROM ranked_products
WHERE product_rank = 1;
This gives the highest-revenue product in every category.
The important SQL concepts here are:
CTE
GROUP BY
RANK()
PARTITION BY
ORDER BY
21. Common SQL Errors in This Project
Error 1: Forgetting GROUP BY
Incorrect:
SELECT
customer_id,
SUM(total_amount)
FROM orders;
If we select customer_id along with an aggregate, we generally need to group by the customer.
Correct:
SELECT
customer_id,
SUM(total_amount) AS revenue
FROM orders
GROUP BY customer_id;
Error 2: Using WHERE with an Aggregate
Incorrect:
SELECT
customer_id,
SUM(total_amount)
FROM orders
GROUP BY customer_id
WHERE SUM(total_amount) > 50000;
The WHERE clause filters individual rows before aggregation.
Use HAVING for filtering aggregated groups:
SELECT
customer_id,
SUM(total_amount) AS revenue
FROM orders
GROUP BY customer_id
HAVING SUM(total_amount) > 50000;
Error 3: Using INNER JOIN When LEFT JOIN Is Required
Suppose we want customers who never ordered.
An INNER JOIN removes customers without matching orders.
Use:
LEFT JOIN
instead.
SELECT
c.customer_id,
c.customer_name
FROM customers c
LEFT JOIN orders o
ON c.customer_id = o.customer_id
WHERE o.order_id IS NULL;
Error 4: Counting Duplicate Rows
When multiple order items exist for one order, careless joins can create duplicate rows.
Instead of blindly using:
COUNT(*)
you may need:
COUNT(DISTINCT o.order_id)
For example:
SELECT
COUNT(DISTINCT o.order_id) AS total_orders
FROM orders o
JOIN order_items oi
ON o.order_id = oi.order_id;
This counts orders rather than order-item rows.
22. SQL Optimization Methods
When the database contains thousands of rows, most queries will work quickly.
But when the database grows to millions or billions of rows, query optimization becomes important.
Optimization 1: Avoid SELECT *
Instead of:
SELECT *
FROM orders;
select only the columns you need:
SELECT
order_id,
customer_id,
order_date,
status
FROM orders;
This reduces unnecessary data processing and transfer.
Optimization 2: Create Indexes
If customers are frequently joined with orders using customer_id, an index can help.
CREATE INDEX idx_orders_customer_id
ON orders(customer_id);
For product joins:
CREATE INDEX idx_order_items_product_id
ON order_items(product_id);
For date-based filtering:
CREATE INDEX idx_orders_order_date
ON orders(order_date);
Indexes can significantly improve suitable lookup and join operations, but they also consume storage and can make inserts and updates more expensive.
23. Optimization 3: Use Date Ranges
Instead of:
WHERE EXTRACT(YEAR FROM order_date) = 2026
a range condition is often preferable:
WHERE order_date >= '2026-01-01'
AND order_date < '2027-01-01'
This can make it easier for the database to use an index on order_date.
24. Optimization 4: Use EXPLAIN
Before optimizing a query, we should understand how the database executes it.
For example:
EXPLAIN
SELECT
customer_id,
COUNT(*)
FROM orders
GROUP BY customer_id;
Depending on the database, the execution plan can show operations such as:
Index Scan
Sequential Scan
Hash Join
Sort
Aggregate
The execution plan helps identify expensive operations.
25. Optimization 5: Avoid Unnecessary Joins
If information from a table is not required, don't join that table.
For example, if we only need the order date:
SELECT
order_id,
order_date
FROM orders;
There is no reason to join customers, products, and order_items.
Every unnecessary operation can increase query complexity and processing cost.
26. Optimization 6: Use CTEs for Complex Analysis
A Common Table Expression can make a complex analytical query easier to understand.
Example:
WITH monthly_sales AS (
SELECT
DATE_TRUNC('month', order_date) AS month,
SUM(total_amount) AS revenue
FROM orders
WHERE status = 'Completed'
GROUP BY DATE_TRUNC('month', order_date)
)
SELECT *
FROM monthly_sales
ORDER BY month;
CTEs improve readability and can make multi-step analytical logic easier to maintain.
Whether a CTE improves performance depends on the database engine and the specific query, so performance should be checked with an execution plan.
27. Final Project Workflow
The complete project follows this process:
Raw E-Commerce Data
↓
Create Database Tables
↓
Clean and Validate Data
↓
Join Related Tables
↓
Calculate Revenue
↓
Analyze Customers
↓
Analyze Products
↓
Analyze Categories
↓
Analyze Monthly Sales
↓
Identify Business Trends
↓
Optimize SQL Queries
↓
Create Reports / Dashboard
28. SQL Concepts Covered
By completing this project, you practice:
SELECT
WHERE
ORDER BY
GROUP BY
HAVING
COUNT
SUM
AVG
MIN
MAX
CASE WHEN
INNER JOIN
LEFT JOIN
DISTINCT
Subqueries
CTEs
RANK()
PARTITION BY
Date Functions
Indexes
EXPLAIN
Query Optimization
29. Business Insights From the Project
After completing the analysis, the company can answer questions such as:
What is our total revenue?
Which products generate the most revenue?
Which products sell the most units?
Who are our highest-value customers?
Which categories perform best?
What is our average order value?
How are sales changing month by month?
How many customers have never purchased?
How many orders are cancelled?
Which product is the top performer in each category?
These insights can then be presented in a dashboard using tools such as Power BI, Tableau, or another visualization platform.
Conclusion
The E-Commerce Sales Analysis project is an excellent practical SQL project because it covers both fundamental and advanced SQL concepts.
You begin with simple operations such as:
SELECT
WHERE
COUNT
SUM
and gradually move toward:
JOIN
CASE WHEN
CTE
Window Functions
RANK
Indexes
EXPLAIN
Query Optimization
The most important lesson is that SQL is not only about writing queries. A good data analytics project combines data understanding, correct calculations, business questions, error handling, and efficient query design.
By completing this project with a realistic dataset, you can build a strong foundation in SQL and apply the same techniques to many other areas such as finance, marketing, healthcare, customer analytics, and business intelligence.