SQL Project - Exploring Trends, Segmentation & KPIs
SQL Project - Exploring Trends, Segmentation & KPIs
SQL
DATA
ANALYTICS
PROJECT
1
Advanced Data Analytics
.
Complex Queries
Window Functions
Subqueries
CTE
Reports
2
Change Over Time, Trends
Year Sales
2023 300
2024 100
2025 200
300
200
100
3
Problem: Analyze sales performance over time.
select*from customers;
select*from products;
select*from sales;
select*from report_customers;
select*from report_products;
SELECT
year(order_date) as order_year,
month(order_date) as order_month,
sum(sales_amount) as total_sales,
sum(quantity) as total_quantity
FROM sales
ORDER BY year(order_date),month(order_date)
4
5
SELECT
SUM(sales_amount) AS total_sales,
SUM(quantity) AS total_quantity
FROM sales
6
Cumulative Analysis
Cumulative value
7
Problem: Calculate the total sales per month and the running
total of overtime sales.
SELECT
order_date,
total_sales,
FROM
SELECT
SUM(sales_amount) AS total_sales
FROM sales
order by total_sales
) AS monthly_sales
ORDER BY order_date;
8
SELECT
total_sales,
FROM (
SELECT
YEAR(order_date) AS order_year,
SUM(sales_amount) AS total_sales,
avg(price) avg_price
9
FROM sales
GROUP BY YEAR(order_date)
ORDER BY YEAR(order_date)
) AS yearly_sales
ORDER BY order_year;
10
Performance Analysis
A 400 400 0
11
Problem: Analyze the yearly performance of each product by
comparing its sales to both its average annual sales and the previous
year's sales.
SELECT
YEAR(s.order_date) AS order_year,
p.product_name,
SUM(s.sales_amount) AS current_sales
FROM sales s
Joined sales with products on
LEFT JOIN products p ON s.product_key = p.product_key product_key using LEFT JOIN
to retain all sales data.
WHERE s.order_date IS NOT NULL
SELECT
case
when current_sales - ROUND( LAG(current_sales) over (partition by
product_name order by order_year)) > 0 then "Increase"
end prev_change
FROM yearly_product_sales
13
Proportional Analysis or Part to whole
A 200 33%
B 300 50%
C 100 17%
17%
33% A
B
C
50%
14
Problem: Which categories contribute the most to overall sales?
with category_sales as (
select p.category,
from category_sales;
15
Data Segmentation
[𝑀𝑒𝑎𝑠𝑢𝑟𝑒] 𝑏𝑦 [𝑀𝑒𝑎𝑠𝑢𝑟𝑒]
[𝑇𝑜𝑡𝑎𝑙 𝑝𝑟𝑜𝑑𝑢𝑐𝑡𝑠 𝑏𝑦 𝑠𝑎𝑙𝑒𝑠 𝑅𝑎𝑛𝑔𝑒]
[𝑇𝑜𝑡𝑎𝑙 𝑐𝑢𝑠𝑡𝑜𝑚𝑒𝑟𝑠 𝑏𝑦 𝐴𝑔𝑒]
Sum Categorize
3 50
Low 7
4 100
5 150
Medium 6
1 200
10 250 High 15
5 300
16
Problem: Segment products into cost ranges and count how many
products fall into each segment.
use data_warehouse;
with product_segment as (
select cost_range,
17
Problem: Group customers into three segments based on their
spending behavior:
- VIP: Customers with at least 12 months of history and spending
more than €5,000.
- Regular: Customers with at least 12 months of history but spending
€5,000 or less.
- New: Customers with a lifespan less than 12 months.
And find the total number of customers by each group
with customer_spending as (
SELECT
c.customer_key,
SUM(s.sales_amount) AS total_spending,
MIN(s.order_date) AS first_order,
MAX(s.order_date) AS last_order,
FROM sales s
ON s.customer_key = c.customer_key
GROUP BY c.customer_key
SELECT
customer_segment,
COUNT(customer_key) AS total_customers
18
FROM (
SELECT
customer_key,
CASE
ELSE 'New'
END AS customer_segment
FROM customer_spending
) AS t
GROUP BY customer_segment
19
Customer Report
20
Task:
1. Gathers essential fields such as names, ages, and transaction details (Base
Query)
SELECT
c.customer_key, c.customer_number,
FROM sales s
ON c.customer_key = s.customer_key
select*from base_query;
21
2) Customer Aggregations: Summarizes key metrics at the customer level.
WITH base_query as (
SELECT
s.order_number,
s.product_key,
s.order_date,
s.sales_amount,
s.quantity,
c.customer_key,
c.customer_number,
FROM sales s
ON c.customer_key = s.customer_key
SELECT
customer_key,
customer_number,
customer_name,
age,
SUM(sales_amount) AS total_sales,
22
SUM(quantity) AS total_quantity,
MAX(order_date) AS last_order_date,
FROM base_query
GROUP BY
customer_key,
customer_number,
customer_name,
age;
23
3. Segments customers into categories (VIP, Regular, New) and age groups.
WITH base_query as (
SELECT
s.order_number,
s.product_key,
s.order_date,
s.sales_amount,
s.quantity,
c.customer_key,
c.customer_number,
FROM sales s
ON c.customer_key = s.customer_key
customer_aggregation AS (
SELECT
customer_key,
customer_number,
customer_name,
age,
24
SUM(sales_amount) AS total_sales,
SUM(quantity) AS total_quantity,
MAX(order_date) AS last_order_date,
FROM base_query
GROUP BY
customer_key,
customer_number,
customer_name,
age)
SELECT
customer_key,
customer_number,
customer_name,
age,
CASE
END AS age_group,
25
-- Customer segment classification
CASE
ELSE 'New'
END AS customer_segment,
last_order_date,
total_orders,
total_sales,
total_quantity,
total_products,
lifespan
FROM customer_aggregation;
26
4. Calculates valuable KPIs:
CREATE view customers_report as -- make the View
WITH base_query as (
SELECT
s.order_number,
s.product_key,
s.order_date,
s.sales_amount,
s.quantity,
c.customer_key,
c.customer_number,
FROM sales s
ON c.customer_key = s.customer_key
customer_aggregation AS (
SELECT
customer_key,
customer_number,
customer_name,
age,
SUM(sales_amount) AS total_sales,
27
SUM(quantity) AS total_quantity,
MAX(order_date) AS last_order_date,
FROM base_query
GROUP BY
customer_key,
customer_number,
customer_name,
age
SELECT
customer_key,
customer_number,
customer_name,
age,
CASE
END AS age_group,
28
-- Customer segment classification
CASE
ELSE 'New'
total_orders,
total_sales,
total_quantity,
total_products,
lifespan,
CASE
END AS avg_order_value,
CASE
END AS avg_monthly_spend
FROM customer_aggregation;
29
-- using view
select age_group,
count(customer_number) as total_customers,
group by age_group;
30
select customer_segment,
count(customer_number) as total_customers,
group by customer_segment;
31
Products Report
Highlights:
1. Gathers essential fields such as product name, category, subcategory, and cost.
2. Segments Products by revenue to identify High-Performers, Mid-Range, or
Low-Performers.
3. Aggregates product-level metrics:
➢ total orders
➢ total sales
➢ total quantity sold
➢ total customers (unique)
➢ lifespan (in months)
4. Calculates valuable KPIs:
➢ recency (months since last sale)
➢ average order revenue (AOR)
➢ average monthly revenue
32
Task:
(1) Base Query: Retrieves core columns from sales and products.
WITH base_query AS (
SELECT
s.order_number,
s.order_date,
s.customer_key,
s.sales_amount,
s.quantity,
p.product_key,
p.product_name,
p.category,
p.subcategory,
p.cost
FROM sales s
ON s.product_key = p.product_key
33
2. Segments Products by revenue to identify High-Performers, Mid-Range, or
Low-Performers.
WITH base_query AS (
SELECT
s.order_number,
s.order_date,
s.customer_key,
s.sales_amount,
s.quantity,
34
p.product_key,
p.product_name,
p.category,
p.subcategory,
p.cost
FROM sales s
ON s.product_key = p.product_key
product_aggregations AS (
product_key,
product_name,
category,
subcategory,
cost,
MAX(order_date) AS last_sale_date,
SUM(sales_amount) AS total_sales,
SUM(quantity) AS total_quantity,
35
ROUND(AVG(CASE WHEN quantity != 0 THEN sales_amount / quantity
ELSE NULL END), 1) AS avg_selling_price
FROM base_query
GROUP BY
product_key,
product_name,
category,
subcategory,
cost
SELECT
product_key,
product_name,
category,
subcategory,
cost,
last_sale_date,
ELSE 'Low-Performer'
END AS product_segment
from product_aggregations;
36
3. Aggregates product-level metrics: total orders, total sales , total quantity sold,
total customers (unique),lifespan (in months).
WITH base_query AS (
SELECT
s.order_number,
s.order_date,
s.customer_key,
s.sales_amount,
s.quantity,
p.product_key,
p.product_name,
p.category,
37
p.subcategory,
p.cost
FROM sales s
ON s.product_key = p.product_key
product_aggregations AS (
SELECT
product_key,
product_name,
category,
subcategory,
cost,
MAX(order_date) AS last_sale_date,
SUM(sales_amount) AS total_sales,
SUM(quantity) AS total_quantity,
FROM base_query
GROUP BY
product_key,
38
product_name,
category,
subcategory,
cost
SELECT
product_key,
product_name,
category,
subcategory,
cost,
last_sale_date,
CASE
ELSE 'Low-Performer'
END AS product_segment,
lifespan,
total_orders,
total_sales,
total_quantity,
39
total_customers,
avg_selling_price
from product_aggregations;
4. Calculates valuable KPIs: recency (months since last sale), average order
revenue (AOR), average monthly revenue.
WITH base_query AS (
SELECT
s.order_number,
s.order_date,
s.customer_key,
s.sales_amount,
40
s.quantity,
p.product_key,
p.product_name,
p.category,
p.subcategory,
p.cost
FROM sales s
ON s.product_key = p.product_key
),
product_aggregations AS (
SELECT
product_key,
product_name,
category,
subcategory,
cost,
MAX(order_date) AS last_sale_date,
SUM(sales_amount) AS total_sales,
SUM(quantity) AS total_quantity,
41
FROM base_query
GROUP BY
product_key,
product_name,
category,
subcategory,
cost)
SELECT
product_key,
product_name,
category,
subcategory,
cost,
last_sale_date,
ELSE 'Low-Performer'
END AS product_segment,
42
ELSE round(total_sales / total_orders,2)
END AS avg_order_revenue,
END AS avg_monthly_revenue
FROM product_aggregations;
Thanks !
43