Thursday, November 12, 2026

How to Analyze Customer Purchase journey and Identify Inactive Customers using SQL

How to find First and Second Purchase Dates and detect Non-Recurring Customers using SQL
Scenario:
Understanding customer purchase behavior is one of the most valuable applications of data analytics. Beyond knowing what customers purchase, businesses often want to understand how quickly customers return after their first purchase and which customers have stopped purchasing altogether.

These insights help organizations measure customer engagement, improve retention strategies, and identify opportunities to increase Customer Lifetime Value (CLV).

In this article, we will use a simple transaction dataset to address below two common business scenarios:

Business Scenario 1: Customer Repeat Purchase Analysis:
Find the First and Second Purchase Dates for each Customer and calculate the number of days between them.

Business Scenario 2: Identifying Non-Recurring Customers:
Identify Non-Recurring (Inactive) Customers who have not made a purchase in the last 90 days or 3 months.

-- Create required Tables
CREATE TABLE dbo.dim_Customers
(
    Customer_ID     INT,
    Customer_Name   VARCHAR(50)
);

CREATE TABLE dbo.dim_Products
(
    Product_ID      INT,
    Product_Name    VARCHAR(50)
);

CREATE TABLE dbo.fact_Transactions
(
    Transact_ID  INT,
    Transact_Date   DATE,
    Customer_ID     INT,
    Product_ID      INT,
    Sales_Amount    DECIMAL(10,2)
);

-- Insert Data into Tables
INSERT INTO dbo.dim_Customers
(
    Customer_ID,
    Customer_Name
)
VALUES
(1,'Sun'),
(2,'Moon'),
(3,'Earth'),
(4,'Water'),
(5,'Sky');

SELECT * FROM dbo.dim_Customers ;


INSERT INTO
dbo.dim_Products
(
    Product_ID,
    Product_Name
)
VALUES
(101,'Radio'),
(102,'Television'),
(103,'Router'),
(104,'Laptop');

SELECT * FROM dbo.dim_Products;


-- TRUNCATE TABLE dbo.fact_Transactions
INSERT INTO dbo.fact_Transactions
(
    Transact_ID,
    Transact_Date,
    Customer_ID,
    Product_ID,
    Sales_Amount
)
VALUES
-- Sun (Only Radio)
(1001,'2026-08-20',1,101,10000),
(1002,'2026-10-15',1,101,12000),

-- Moon (Radio + Television)
(1003,'2026-07-20',2,101,15000),
(1004,'2026-10-05',2,102,30000),

-- Earth (Only Radio)
(1005,'2026-02-10',3,101,8000),

-- Water (Only Laptop)
(1006,'2026-03-25',4,104,70000),

-- Sky (Radio + Router)
(1007,'2026-08-30',5,101,9000),
(1008,'2026-11-01',5,103,5000);

SELECT * FROM dbo.fact_Transactions

---------------------------------------------------------

Business Scenario 1: Customer Repeat Purchase Analysis:
Business to understand how quickly customers return after making their first purchase. The time gap between the first and second purchases is a key indicator of customer engagement and purchasing behavior.

Customers who return quickly are often more engaged and have a higher likelihood of becoming long-term customers.

Business Benefits:
  • Measure Customer Engagement by tracking how quickly customers make a second purchase.
  • Identify High-Value Repeat Buyers who demonstrate strong purchasing behavior.
  • Improve Marketing Timing by understanding the optimal period for follow-up campaigns.
  • Support Customer Retention Strategies using customer purchase patterns.
  • Increase Customer Lifetime Value (CLV) through proactive engagement.
We can achieve this Scenario using the below SQL Query:

WITH CTE_Ranked_Purchases AS
(
    SELECT
        f.Customer_ID,
        f.Transact_Date,
        p.Product_Name,
        ROW_NUMBER() OVER
        (
            PARTITION BY f.Customer_ID
            ORDER BY f.Transact_Date ASC
        ) AS RN -- Purchase Sequence Number
    FROM dbo.fact_Transactions f
    INNER JOIN dbo.dim_Products p
        ON f.Product_ID = p.Product_ID
)

SELECT
    c.Customer_ID,
    c.Customer_Name,

    MAX(CASE WHEN RN = 1 THEN Transact_Date END) AS First_Purchase_Date,
    MAX(CASE WHEN RN = 1 THEN Product_Name END) AS First_Purchase_Product,

    MAX(CASE WHEN RN = 2 THEN Transact_Date END) AS Second_Purchase_Date,
    MAX(CASE WHEN RN = 2 THEN Product_Name END) AS Second_Purchase_Product,

    DATEDIFF
    (
        DAY,
        MAX(CASE WHEN RN = 1 THEN Transact_Date END),
        MAX(CASE WHEN RN = 2 THEN Transact_Date END)
    ) AS Days_Between_Purchases
FROM CTE_Ranked_Purchases rp
INNER JOIN dbo.dim_Customers c
    ON rp.Customer_ID = c.Customer_ID
WHERE RN <= 2 -- Keep only First and Second Purchases
GROUP BY
    c.Customer_ID,
    c.Customer_Name
HAVING COUNT(*) = 2 -- Customers having both 1st and 2nd Purchases
ORDER BY
    c.Customer_ID;

#Result:

Business Scenario 2: Identifying Non-Recurring Customers:
Customer retention is often more cost-effective than acquiring new customers. By identifying customers who have not purchased within a defined period, business can proactively launch retention campaigns, improve engagement, and encourage repeat purchases.

In this scenario, a customer is considered Non-Recurring (Inactive) if they have not made a purchase in the Last 90 days or last 3 months.

Business Benefits:
  • Identify Inactive Customers who have stopped purchasing.
  • Launch Targeted Retention Campaigns to re-engage dormant customers.
  • Improve Customer Retention through timely outreach.
  • Optimize Marketing Spend by focusing on customers most likely to return.
  • Monitor Customer Health using purchase recency.
  • Support Data-Driven Decision-Making for customer engagement initiatives.
We can achieve this Scenario using the below SQL Query:

WITH CTE_LastPurchase AS
(
    SELECT
        f.Customer_ID,
        f.Transact_Date,
        p.Product_Name,
        ROW_NUMBER() OVER
        (
            PARTITION BY f.Customer_ID
            ORDER BY f.Transact_Date DESC
        ) AS RN  -- Purchase Sequence Number
    FROM dbo.fact_Transactions f
    INNER JOIN dbo.dim_Products p
        ON f.Product_ID = p.Product_ID
)

SELECT
    c.Customer_ID,
    c.Customer_Name,
    lp.Transact_Date AS Last_Purchase_Date,
    lp.Product_Name AS Last_Purchase_Product,
    DATEDIFF
    (
        DAY,
        lp.Transact_Date,
        GETDATE()
    ) AS Days_Inactive
FROM CTE_LastPurchase lp
INNER JOIN dbo.dim_Customers c
    ON lp.Customer_ID = c.Customer_ID
WHERE lp.RN = 1 -- Most recent Purchase
    -- Option 1: Inactive for more than 90 Days
    AND lp.Transact_Date < DATEADD(DAY, -90, GETDATE())
    -- Option 2: Inactive for more than 3 Calendar Months
    -- AND lp.Transact_Date < DATEADD(MONTH, -3, GETDATE())
ORDER BY
    c.Customer_ID;

#Result:


--------------------------------------------------------------------------------------------------------
Thanks, TAMATAM ; Business Intelligence & Analytics Professional
--------------------------------------------------------------------------------------------------------

How to find Customers who only Purchased a specific Product using SQL

How to Identify the Single-Category Loyal Customers Using SQL
Scenario:
In today's data-driven business environment, understanding customer purchasing behavior is critical for driving revenue growth and improving customer engagement. 
One common analytical requirement is identifying customers who purchase exclusively from a single product category and have never explored other product offerings. 
These customers often represent highly loyal segments with distinct buying patterns, making them valuable candidates for targeted marketing and growth initiatives.

Consider a retailer offering multiple product categories such as Radios, Televisions, Routers, and Laptops. The business wants to identify customers who have purchased only Radio products throughout their transaction history and determine the revenue generated by this customer segment. 
By leveraging a simple yet highly optimized SQL aggregation technique, organizations can efficiently analyze large transaction datasets and uncover these loyal customers.

In this article, we will explore an SQL solution that identifies customers who have purchased only Radio products, calculates their revenue contribution, and demonstrates how a simple query can deliver meaningful business insights from transactional data.

-- Create required Tables
CREATE TABLE dbo.dim_Customers
(
    Customer_ID     INT,
    Customer_Name   VARCHAR(50)
);

CREATE TABLE dbo.dim_Products
(
    Product_ID      INT,
    Product_Name    VARCHAR(50)
);

CREATE TABLE dbo.fact_Transactions
(
    Transact_ID  INT,
    Transact_Date   DATE,
    Customer_ID     INT,
    Product_ID      INT,
    Sales_Amount    DECIMAL(10,2)
);

-- Insert Data into Tables
INSERT INTO dbo.dim_Customers
(
    Customer_ID,
    Customer_Name
)
VALUES
(1,'Sun'),
(2,'Moon'),
(3,'Earth'),
(4,'Water'),
(5,'Sky');

SELECT * FROM dbo.dim_Customers ;


INSERT INTO
dbo.dim_Products
(
    Product_ID,
    Product_Name
)
VALUES
(101,'Radio'),
(102,'Television'),
(103,'Router'),
(104,'Laptop');

SELECT * FROM dbo.dim_Products;


-- TRUNCATE TABLE dbo.fact_Transactions
INSERT INTO dbo.fact_Transactions
(
    Transact_ID,
    Transact_Date,
    Customer_ID,
    Product_ID,
    Sales_Amount
)
VALUES
-- Sun (Only Radio)
(1001,'2026-08-20',1,101,10000),
(1002,'2026-10-15',1,101,12000),

-- Moon (Radio + Television)
(1003,'2026-07-20',2,101,15000),
(1004,'2026-10-05',2,102,30000),

-- Earth (Only Radio)
(1005,'2026-02-10',3,101,8000),

-- Water (Only Laptop)
(1006,'2026-03-25',4,104,70000),

-- Sky (Radio + Router)
(1007,'2026-08-30',5,101,9000),
(1008,'2026-11-01',5,103,5000);

SELECT * FROM dbo.fact_Transactions

---------------------------------------------------------
Now we can use the below SQL Query to Identify the customers who have purchased only the Product is Radio and not any other Products:

SELECT
    c.Customer_ID,
    c.Customer_Name,
    MAX(p.Product_Name) AS Product_Name,
    SUM(f.Sales_Amount) AS Revenue
FROM dbo.fact_Transactions f
INNER JOIN dbo.dim_Customers c
    ON c.Customer_ID = f.Customer_ID
INNER JOIN dbo.dim_Products p
    ON p.Product_ID = f.Product_ID
GROUP BY
    c.Customer_ID,
    c.Customer_Name
HAVING
    MIN(f.Product_ID) = 101 -- 'Radio'
    AND MAX(f.Product_ID) = 101; 

#Result:

We can use the below query to Identify the customers who have purchased only the Product is Radio and not any other Products in last 90 days:

SELECT
    c.Customer_ID,
    c.Customer_Name,
    MAX(p.Product_Name) AS Product_Name,
    SUM(f.Sales_Amount) AS Revenue
FROM dbo.fact_Transactions f
INNER JOIN dbo.dim_Customers c
    ON c.Customer_ID = f.Customer_ID
INNER JOIN dbo.dim_Products p
    ON p.Product_ID = f.Product_ID
WHERE
    -- Option 1: Last 90 Days
    f.Transact_Date >= DATEADD(DAY, -90, GETDATE())

    -- Option 2: Last 3 Calendar Months
    -- f.Transact_Date >= DATEADD(MONTH, -3, GETDATE())
GROUP BY
    c.Customer_ID,
    c.Customer_Name
HAVING
    MIN(f.Product_ID) = 101 -- 'Radio'
    AND MAX(f.Product_ID) = 101; 

#Result:

Business Value Creation:
  • Identify Product Loyalty: Discover customers who consistently purchase only one product category, providing valuable insights into customer preferences and product affinity.
  • Increase Cross-Sell Opportunities: Target loyal customers with complementary products and services to encourage broader product adoption and increase revenue.
  • Improve Marketing Effectiveness: Develop focused campaigns based on customer purchasing behavior rather than relying on generic audience targeting.
  • Measure Revenue Contribution: Quantify the revenue generated by loyal customer segments and evaluate their business impact.
  • Enhance Customer Segmentation: Build more accurate customer profiles and support personalized engagement strategies.
  • Support Data-Driven Decision Making: Enable sales, marketing, and product teams to make informed decisions using actionable insights derived from transactional data.
  • Increase Customer Lifetime Value (CLV): Identify opportunities to deepen customer relationships and maximize long-term business value through targeted recommendations and retention strategies.
--------------------------------------------------------------------------------------------------------
Thanks, TAMATAM ; Business Intelligence & Analytics Professional
--------------------------------------------------------------------------------------------------------

Wednesday, November 11, 2026

How to Calculate Yearly, Quarterly and Monthly Sales Growth using SQL

How to Calculate YoY, QoQ and MoM Sales Growth in SQL Server
Scenario:
In business intelligence and analytics projects, understanding sales growth trends is critical for measuring product performance. Three of the most commonly used growth metrics are:
  1. Month-over-Month (MoM) Sales Growth
  2. Quarter-over-Quarter (QoQ) Sales Growth
  3. Year-over-Year (YoY) Sales Growth
These metrics help analysts compare current sales against previous periods and identify growth patterns.

In this article, we'll use the sample dataset below to calculate MoM, QoQ, and YoY sales growth using SQL.

/* Create Source Table */
USE [db_MyAnalytics]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

/* Check and Drop table if already Exists */
IF OBJECT_ID('dbo.fact_ProductSales', 'U') IS NOT NULL
BEGIN
    DROP TABLE dbo.fact_ProductSales;
END
GO

CREATE TABLE dbo.fact_ProductSales
(
    Sales_Date     DATE NULL,
    Product_Name   VARCHAR(50) NULL,
    Sales_Amount   DECIMAL(10,2) NULL
) ON [PRIMARY];
GO

/* Check and Truncate table if already Exists */
IF OBJECT_ID('dbo.fact_ProductSales', 'U') IS NOT NULL
BEGIN
    TRUNCATE TABLE dbo.fact_ProductSales;
END
GO

/* Insert Data to Table */
INSERT INTO [dbo].[fact_ProductSales] 
(
    [Sales_Date],
    [Product_Name],
    [Sales_Amount]
)
VALUES
('2023-01-01','Radio',10000),
('2023-02-01','Radio',12000),
('2023-03-01','Radio',13000),
('2023-04-01','Radio',15000),
('2023-05-01','Radio',17000),
('2023-06-01','Radio',18000),

('2024-01-01','Radio',14000),
('2024-02-01','Radio',15500),
('2024-03-01','Radio',16000),
('2024-04-01','Radio',17500),
('2024-05-01','Radio',19000),
('2024-06-01','Radio',21000),

('2023-01-01','Television',50000),
('2023-02-01','Television',52000),
('2023-03-01','Television',55000),
('2023-04-01','Television',57000),
('2023-05-01','Television',60000),
('2023-06-01','Television',62000),

('2024-01-01','Television',65000),
('2024-02-01','Television',67000),
('2024-03-01','Television',70000),
('2024-04-01','Television',72000),
('2024-05-01','Television',76000),
('2024-06-01','Television',80000);

SELECT * FROM [dbo].[fact_ProductSales] 
GO

#Result:
------------------------------------------------------------
/* 
Understanding Growth Formula:
Growth % = (Current Period Sales - Previous Period Sales)/Previous Period Sales * 100
*/

1. Month-over-Month (MoM) Sales Growth:
Month-over-Month (MoM) Growth compares the current month's sales with previous month's sales. It helps businesses to measure short-term performance changes and identify emerging trends.
MoM analysis is useful for monitoring the immediate impact of marketing campaigns, product launches, seasonal promotions, pricing changes, or other business initiatives. 
Since the comparison period is only one month, it provides a near real-time view of business performance.

Example:
January Sales = $10,000
February Sales = $12,000

MoM Growth = 20%
This indicates that sales increased by 20% compared to the previous month.

WITH CTE_Monthly_Sales AS
(
    SELECT
        Product_Name,
        Sales_Date,
        Sales_Amount,
        LAG(Sales_Amount) OVER
        (
            PARTITION BY Product_Name
            ORDER BY Sales_Date
        ) AS PrevMonth_Sales
    FROM [dbo].[fact_ProductSales]
)
SELECT
    Product_Name,
    Sales_Date,
    Sales_Amount,
    PrevMonth_Sales,
    (Sales_Amount - PrevMonth_Sales) AS Sales_Variance,
    ROUND(
        ((Sales_Amount - PrevMonth_Sales) * 100.0)
        / NULLIF(PrevMonth_Sales,0),
        2
        ) AS MoM_Growth_Percent
FROM CTE_Monthly_Sales
ORDER BY Product_Name, Sales_Date;

#Result:
------------------------------------------------------------
2. Quarter-over-Quarter (QoQ) Sales Growth:
Quarter-over-Quarter (QoQ) Growth compares sales from the current quarter with previous quarter. Since a quarter typically consists of three months, QoQ analysis helps smooth out monthly fluctuations and provides a broader view of business performance.

Organizations often use QoQ metrics to evaluate strategic initiatives, assess departmental performance, and measure progress against quarterly business objectives. It is especially useful for executive reporting and financial analysis.

Example:
Q1 Sales = $150,000
Q2 Sales = $180,000

QoQ Growth = 20%
This indicates that sales increased by 20% compared to the previous quarter.

WITH CTE_Quarterly_Sales AS
(
    SELECT
        Product_Name,
        YEAR(Sales_Date) AS Sales_Year,
        DATEPART(QUARTER, Sales_Date) AS Qtr_No,
        SUM(Sales_Amount) AS Qtr_Sales,
        LAG(SUM(Sales_Amount)) OVER
        (
            PARTITION BY Product_Name
            ORDER BY YEAR(Sales_Date), DATEPART(QUARTER, Sales_Date)
        ) AS PrevQtr_Sales
    FROM dbo.fact_ProductSales
    GROUP BY
        Product_Name,
        YEAR(Sales_Date),
        DATEPART(QUARTER, Sales_Date)
)
SELECT
    Product_Name,
    Sales_Year,
    Qtr_No,
    Qtr_Sales,
    PrevQtr_Sales,
    (Qtr_Sales - PrevQtr_Sales) AS Sales_Variance,
    ROUND
    (
        ((Qtr_Sales - PrevQtr_Sales) * 100.0)
        / NULLIF(PrevQtr_Sales, 0),
        2
    ) AS QoQ_Growth_Percent
FROM CTE_Quarterly_Sales
ORDER BY Product_Name, Sales_Year, Qtr_No;

#Result:
------------------------------------------------------------
3. Year-over-Year (YoY) Sales Growth:
Year-over-Year (YoY) Growth compares sales for a specific period against the same period in the previous year. This comparison helps businesses evaluate long-term growth trends and overall business performance.
YoY is considered as one of the most important Key Performance Indicators (KPIs) because it minimizes the impact of seasonality.
 
For example, comparing Dec sales with Nov sales may not provide an accurate comparison due to seasonal factors such as holiday shopping. However, comparing Dec-2024 with Dec-2023 helps eliminate seasonality and provides a more accurate measure of true business growth.

YoY analysis is widely used by business leaders, analysts, investors, and finance teams to assess whether a company is growing, maintaining, or losing market momentum.

Example:
Q1 2023 Sales = $500,000
Q1 2024 Sales = $625,000

YoY Growth = 25%
This indicates that sales grew by 25% compared to the same quarter in the previous year.

Why YoY Growth is Important:
  • Eliminates seasonal variations in sales.
  • Measures long-term business performance.
  • Provides a more accurate view of growth trends.
  • Commonly used in financial reporting and executive dashboards.
  • Helps stakeholders assess the overall health of the business.
WITH CTE_Yearly_Sales AS
(
    SELECT
        Product_Name,
        YEAR(Sales_Date) AS Sales_Year,
        SUM(Sales_Amount) AS Yearly_Sales,
        LAG(SUM(Sales_Amount)) OVER
        (
            PARTITION BY Product_Name
            ORDER BY YEAR(Sales_Date)
        ) AS PrevYear_Sales
    FROM dbo.fact_ProductSales
    GROUP BY Product_Name, YEAR(Sales_Date)
)
SELECT
    Product_Name,
    Sales_Year,
    Yearly_Sales,
    PrevYear_Sales,
    (Yearly_Sales - PrevYear_Sales) AS Sales_Variance,
    ROUND
    (
        ((Yearly_Sales - PrevYear_Sales) * 100.0)
        / NULLIF(PrevYear_Sales, 0),
        2
    ) AS YoY_Growth_Percent
FROM CTE_Yearly_Sales
ORDER BY Product_Name, Sales_Year;

#Result:


--------------------------------------------------------------------------------------------------------
Thanks, TAMATAM ; Business Intelligence & Analytics Professional
--------------------------------------------------------------------------------------------------------

Featured Post from this Blog

How to compare Current Snapshot Data with Previous Snapshot in Power BI

How to Dynamically compare two Snapshots Data in Power BI Scenario: Suppose we have a sample Sales data, which is stored with Monthly Snapsh...

Popular Posts from this Blog