Files
SQL/exercises/02-customer-analytics
Alphaeus Mote aa803bd3bd Expand to Business Analytics: Add Customer, Sales, and KPI models
Major expansion from fraud detection to comprehensive business analytics:

DATABASE CHANGES:
- Renamed database from 'fraud_detection' to 'business_analytics'
- Renamed user from 'fraud_analyst' to 'data_analyst'
- Expanded from 20 to 39 tables across 4 business models

NEW MODELS (19 tables):
1. Customer Analytics (5 tables):
   - customer_segments, customer_lifetime_value, churn_predictions
   - customer_satisfaction, engagement_metrics

2. Sales & Revenue Analytics (6 tables):
   - product_catalog, sales_transactions, sales_targets
   - sales_performance, revenue_forecasts

3. KPI & Metrics (8 tables):
   - kpi_definitions, daily_metrics, monthly_summaries
   - trend_analysis, dashboard_snapshots
   - report_definitions, report_executions, data_quality_checks

DATA GENERATION:
- Extended generate_data.sh with 6 new steps (now 15 total)
- Added CLV calculations for all customers
- Added churn predictions based on transaction recency
- Added 30K customer satisfaction surveys
- Added 1M sales transactions linked to 24 products
- Added 90 days of daily KPI metrics
- Added 24 months of business summaries

SQL EXERCISES (3 new levels):
- Level 2: Customer Analytics (10 exercises + 3 challenges)
- Level 3: Sales & Revenue Analysis (12 exercises + 3 challenges)
- Level 4: KPI Dashboards & Metrics (12 exercises + 3 challenges)

DOCUMENTATION:
- Updated README.md with business analytics focus
- Updated QUICKSTART.md with new data generation steps
- Updated SETUP_COMPLETE.md with 39-table architecture
- Added DATA_MODELS.md with complete model specifications
- Added WHATS_NEW.md with migration guide

SEED DATA:
- Added 8 customer segments (VIP, High Value, etc.)
- Added 24 products across 5 categories
- Added 16 KPI definitions across 4 categories
- Added 8 standard report definitions

All changes maintain idempotency and backward compatibility with existing fraud detection functionality.
2025-10-23 14:17:12 -04:00
..

Level 2: Customer Analytics

Introduction

Learn to analyze customer behavior, calculate lifetime value, identify churn risks, and segment customers - essential skills for Data Analysts working with customer data.

Learning Objectives

  • Calculate customer lifetime value (CLV)
  • Identify at-risk customers
  • Segment customers by behavior
  • Analyze satisfaction trends
  • Track engagement metrics

Exercise 2.1: Customer Segmentation

Objective: Find the distribution of customers across segments

SELECT 
    cs.segment_name,
    COUNT(clv.customer_id) as customer_count,
    AVG(clv.clv_score) as avg_clv_score,
    SUM(clv.total_revenue) as total_segment_revenue
FROM customer_segments cs
LEFT JOIN customer_lifetime_value clv ON cs.segment_id = clv.segment_id
GROUP BY cs.segment_id, cs.segment_name
ORDER BY total_segment_revenue DESC;

Expected Result: Segment breakdown with counts and revenue


Exercise 2.2: High-Value Customers

Objective: Identify top 10 customers by lifetime value

-- Your query here

Hint: Use customer_lifetime_value table and ORDER BY

Solution:

SELECT 
    c.customer_id,
    c.first_name,
    c.last_name,
    c.email,
    clv.total_revenue,
    clv.total_transactions,
    clv.clv_score,
    cs.segment_name
FROM customer_lifetime_value clv
JOIN customers c ON clv.customer_id = c.customer_id
JOIN customer_segments cs ON clv.segment_id = cs.segment_id
ORDER BY clv.clv_score DESC
LIMIT 10;

Exercise 2.3: Churn Risk Analysis

Objective: Find customers at CRITICAL or HIGH churn risk

-- Your query here

Solution:

SELECT 
    c.customer_id,
    c.first_name,
    c.last_name,
    c.email,
    cp.churn_probability,
    cp.risk_level,
    cp.days_since_last_transaction,
    cp.engagement_score
FROM churn_predictions cp
JOIN customers c ON cp.customer_id = c.customer_id
WHERE cp.risk_level IN ('CRITICAL', 'HIGH')
ORDER BY cp.churn_probability DESC;

Objective: Calculate average NPS score by month

-- Your query here

Hint: Use DATE_TRUNC or EXTRACT to group by month

Solution:

SELECT 
    DATE_TRUNC('month', survey_date) as month,
    COUNT(*) as survey_count,
    AVG(nps_score) as avg_nps,
    AVG(csat_score) as avg_csat,
    COUNT(CASE WHEN sentiment = 'POSITIVE' THEN 1 END) as positive_count,
    COUNT(CASE WHEN sentiment = 'NEGATIVE' THEN 1 END) as negative_count
FROM customer_satisfaction
GROUP BY DATE_TRUNC('month', survey_date)
ORDER BY month DESC;

Exercise 2.5: Engagement Score Analysis

Objective: Find customers with declining engagement

-- Your query here

Hint: Compare recent engagement to historical average

Solution:

WITH recent_engagement AS (
    SELECT 
        customer_id,
        AVG(engagement_score) as recent_score
    FROM engagement_metrics
    WHERE metric_date >= CURRENT_DATE - INTERVAL '30 days'
    GROUP BY customer_id
),
historical_engagement AS (
    SELECT 
        customer_id,
        AVG(engagement_score) as historical_score
    FROM engagement_metrics
    WHERE metric_date < CURRENT_DATE - INTERVAL '30 days'
    GROUP BY customer_id
)
SELECT 
    c.customer_id,
    c.first_name,
    c.last_name,
    re.recent_score,
    he.historical_score,
    (re.recent_score - he.historical_score) as score_change
FROM customers c
JOIN recent_engagement re ON c.customer_id = re.customer_id
JOIN historical_engagement he ON c.customer_id = he.customer_id
WHERE re.recent_score < he.historical_score
ORDER BY score_change ASC
LIMIT 20;

Exercise 2.6: Customer Cohort Analysis

Objective: Analyze customer retention by registration cohort

-- Your query here

Solution:

SELECT 
    DATE_TRUNC('month', c.registration_date) as cohort_month,
    COUNT(DISTINCT c.customer_id) as total_customers,
    COUNT(DISTINCT CASE WHEN cp.risk_level = 'LOW' THEN c.customer_id END) as active_customers,
    COUNT(DISTINCT CASE WHEN cp.risk_level IN ('HIGH', 'CRITICAL') THEN c.customer_id END) as at_risk_customers,
    ROUND(100.0 * COUNT(DISTINCT CASE WHEN cp.risk_level = 'LOW' THEN c.customer_id END) / 
          COUNT(DISTINCT c.customer_id), 2) as retention_rate
FROM customers c
LEFT JOIN churn_predictions cp ON c.customer_id = cp.customer_id
WHERE c.registration_date >= CURRENT_DATE - INTERVAL '12 months'
GROUP BY DATE_TRUNC('month', c.registration_date)
ORDER BY cohort_month DESC;

Exercise 2.7: Customer Lifetime Value by Segment

Objective: Compare CLV metrics across customer segments

-- Your query here

Solution:

SELECT 
    cs.segment_name,
    COUNT(clv.customer_id) as customer_count,
    MIN(clv.clv_score) as min_clv,
    AVG(clv.clv_score) as avg_clv,
    MAX(clv.clv_score) as max_clv,
    PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY clv.clv_score) as median_clv,
    SUM(clv.total_revenue) as total_revenue,
    AVG(clv.total_transactions) as avg_transactions
FROM customer_segments cs
JOIN customer_lifetime_value clv ON cs.segment_id = clv.segment_id
GROUP BY cs.segment_id, cs.segment_name
ORDER BY avg_clv DESC;

Exercise 2.8: Satisfaction by Category

Objective: Analyze satisfaction scores by feedback category

-- Your query here

Solution:

SELECT 
    category,
    COUNT(*) as feedback_count,
    AVG(nps_score) as avg_nps,
    AVG(csat_score) as avg_csat,
    ROUND(100.0 * COUNT(CASE WHEN sentiment = 'POSITIVE' THEN 1 END) / COUNT(*), 2) as positive_pct,
    ROUND(100.0 * COUNT(CASE WHEN sentiment = 'NEGATIVE' THEN 1 END) / COUNT(*), 2) as negative_pct
FROM customer_satisfaction
GROUP BY category
ORDER BY avg_nps DESC;

Exercise 2.9: Customer Engagement Patterns

Objective: Find most engaged customers in the last 30 days

-- Your query here

Solution:

SELECT 
    c.customer_id,
    c.first_name,
    c.last_name,
    SUM(em.login_count) as total_logins,
    SUM(em.page_views) as total_page_views,
    SUM(em.time_spent_minutes) as total_time_spent,
    AVG(em.engagement_score) as avg_engagement_score
FROM customers c
JOIN engagement_metrics em ON c.customer_id = em.customer_id
WHERE em.metric_date >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY c.customer_id, c.first_name, c.last_name
HAVING AVG(em.engagement_score) > 75
ORDER BY avg_engagement_score DESC
LIMIT 20;

Exercise 2.10: Churn Prevention Priority List

Objective: Create a priority list for customer retention efforts

-- Your query here

Hint: Combine churn risk with customer value

Solution:

SELECT 
    c.customer_id,
    c.first_name,
    c.last_name,
    c.email,
    clv.clv_score,
    clv.total_revenue,
    cp.churn_probability,
    cp.risk_level,
    cp.days_since_last_transaction,
    (clv.clv_score * cp.churn_probability / 100) as retention_priority_score
FROM customers c
JOIN customer_lifetime_value clv ON c.customer_id = clv.customer_id
JOIN churn_predictions cp ON c.customer_id = cp.customer_id
WHERE cp.risk_level IN ('HIGH', 'CRITICAL')
  AND clv.clv_score > 1000
ORDER BY retention_priority_score DESC
LIMIT 50;

Challenge Exercises

Challenge 2.1: Customer Journey Analysis

Create a query that shows the customer journey from registration to current status, including:

  • Registration date
  • First transaction date
  • Total transactions
  • Current segment
  • Churn risk
  • Latest satisfaction score

Challenge 2.2: Segment Migration Analysis

Identify customers who have moved between segments over time (requires historical CLV data)

Challenge 2.3: Engagement Correlation

Analyze the correlation between engagement scores and satisfaction scores


Next Steps

Once you're comfortable with customer analytics, move on to:

  • Level 3: Sales & Revenue Analysis
  • Level 4: KPI Dashboards & Metrics