What decision or uncertainty are we trying to reduce?
Applied SQL Analysis.
You know the SQL tools. Now learn the reusable analysis patterns businesses ask for: retention, funnels, churn, RFM, LTV, attribution, experiments, inventory and risk.
Business analysis becomes easier when you recognize recurring patterns: define the population, choose the grain, calculate the signal, compare it with the right baseline, then decide what the business should do.
Every pattern follows the same five questions.
What should one input and output row represent?
Which joins, grouping or windows create the answer?
What does the returned number actually mean?
What should change if the signal is real?
Understand who stays, who leaves, and how behavior changes.
Cohort Analysis
Do customers acquired in different months behave differently later?
A January onboarding change launched. Compare January signups with December and February cohorts to see whether later retention improved.
SQL patternShow example query+
WITH first_month AS (
SELECT customer_id, DATE_TRUNC('month', MIN(order_date)) AS cohort_month
FROM orders GROUP BY customer_id
), activity AS (
SELECT o.customer_id, f.cohort_month,
DATE_TRUNC('month', o.order_date) AS activity_month
FROM orders o JOIN first_month f USING (customer_id)
)
SELECT cohort_month, activity_month, COUNT(DISTINCT customer_id) AS active_customers
FROM activity
GROUP BY 1, 2; Use it to compare customer quality across acquisition periods, campaigns or product releases.
If February retention collapses while January is healthy, investigate February acquisition quality or onboarding changes.
Retention Analysis
What percentage of users return after their first activity?
A delivery app wants to know whether first-time customers become repeat users after their first order.
SQL patternShow example query+
WITH first_order AS (
SELECT customer_id, MIN(order_date) AS first_date
FROM orders GROUP BY customer_id
)
SELECT
DATE_PART('week', o.order_date - f.first_date) AS week_number,
COUNT(DISTINCT o.customer_id) AS retained_customers
FROM orders o JOIN first_order f USING (customer_id)
GROUP BY 1 ORDER BY 1; Retention is a product-health signal: growth from acquisition is fragile if users do not return.
A sharp Week-1 drop suggests the first experience or early value proposition needs attention.
Funnel Analysis
Where do users drop out of a multi-step journey?
Checkout conversion falls after a mobile release. Compare each funnel step instead of only looking at final purchases.
SQL patternShow example query+
SELECT
COUNT(DISTINCT CASE WHEN event_name='visit' THEN user_id END) AS visits,
COUNT(DISTINCT CASE WHEN event_name='signup' THEN user_id END) AS signups,
COUNT(DISTINCT CASE WHEN event_name='checkout' THEN user_id END) AS checkouts,
COUNT(DISTINCT CASE WHEN event_name='purchase' THEN user_id END) AS purchases
FROM events
WHERE event_date >= CURRENT_DATE - INTERVAL '30 days'; Pinpoints the stage causing conversion loss instead of blaming the whole journey.
If checkout starts are stable but purchases fall, investigate payments or checkout errors before acquisition.
Customer Churn Analysis
Which customers have become inactive beyond an agreed threshold?
A subscription-like commerce business treats 60 days without an order as churn risk.
SQL patternShow example query+
SELECT customer_id,
MAX(order_date) AS last_order_date,
CURRENT_DATE - MAX(order_date)::date AS days_inactive,
CASE
WHEN CURRENT_DATE - MAX(order_date)::date > 60 THEN 'Churned'
WHEN CURRENT_DATE - MAX(order_date)::date > 30 THEN 'At risk'
ELSE 'Active'
END AS lifecycle_state
FROM orders
GROUP BY customer_id; Turns inactivity into an actionable customer list for win-back and lifecycle campaigns.
Prioritize high-value at-risk customers before they cross the churn threshold.
Customer Segmentation
Which groups deserve different product or marketing treatment?
A retailer wants different messaging for new customers, repeat buyers and high-value customers.
SQL patternShow example query+
SELECT customer_id,
COUNT(*) AS orders,
SUM(amount_bdt) AS spend,
CASE
WHEN SUM(amount_bdt) >= 50000 THEN 'VIP'
WHEN COUNT(*) >= 5 THEN 'Frequent'
WHEN COUNT(*) = 1 THEN 'New'
ELSE 'Occasional'
END AS segment
FROM orders
GROUP BY customer_id; Segmentation makes one-size-fits-all campaigns less wasteful.
Offer VIP service benefits to high-value customers while using education or incentives for new users.
RFM Analysis
Who is recent, frequent and valuable?
An e-commerce team needs a simple, interpretable loyalty segmentation without machine learning.
SQL patternShow example query+
WITH rfm AS (
SELECT customer_id,
CURRENT_DATE - MAX(order_date)::date AS recency_days,
COUNT(*) AS frequency,
SUM(amount_bdt) AS monetary
FROM orders GROUP BY customer_id
)
SELECT *,
NTILE(5) OVER (ORDER BY recency_days DESC) AS r_score,
NTILE(5) OVER (ORDER BY frequency) AS f_score,
NTILE(5) OVER (ORDER BY monetary) AS m_score
FROM rfm; Creates practical customer tiers from purchase behavior.
Target 5-5-5 customers with loyalty rewards and high-M but low-R customers with win-back offers.
Sessionization Analysis
How do raw events become separate visits or sessions?
Product events arrive as a continuous clickstream. A 30-minute inactivity gap defines a new session.
SQL patternShow example query+
WITH gaps AS (
SELECT user_id, event_time,
event_time - LAG(event_time) OVER (PARTITION BY user_id ORDER BY event_time) AS gap
FROM events
), flags AS (
SELECT *, CASE WHEN gap IS NULL OR gap > INTERVAL '30 minutes' THEN 1 ELSE 0 END AS new_session
FROM gaps
)
SELECT *, SUM(new_session) OVER (PARTITION BY user_id ORDER BY event_time) AS session_id
FROM flags; Lets analysts measure sessions, visit duration and actions per visit from event logs.
If session length grows but conversion falls, users may be struggling rather than engaging more.
Connect customer behavior to money and commercial decisions.
Basket / Affinity Analysis
Which products are frequently bought together?
A marketplace wants to recommend complementary products during checkout.
SQL patternShow example query+
SELECT a.product_id AS product_a, b.product_id AS product_b,
COUNT(DISTINCT a.order_id) AS baskets
FROM order_items a
JOIN order_items b
ON a.order_id = b.order_id
AND a.product_id < b.product_id
GROUP BY 1, 2
ORDER BY baskets DESC; Reveals co-purchase patterns for bundles, recommendations and merchandising.
Bundle high-affinity pairs or place the second item in cross-sell recommendations.
Customer Lifetime Value (LTV)
How much value does a customer or cohort generate over time?
Marketing needs to know whether a ৳1,200 acquisition cost is justified by downstream customer revenue.
SQL patternShow example query+
SELECT customer_id,
SUM(net_revenue_bdt) AS lifetime_revenue,
COUNT(DISTINCT order_id) AS lifetime_orders,
MIN(order_date) AS first_order,
MAX(order_date) AS latest_order
FROM orders
GROUP BY customer_id; LTV connects acquisition spend to long-term customer economics.
Pay more to acquire channels or segments whose realized LTV supports the higher CAC.
Acquisition & Attribution
Which channels bring users who actually convert and create value?
Two channels acquire the same number of customers, but one produces much higher repeat revenue.
SQL patternShow example query+
SELECT acquisition_channel,
COUNT(DISTINCT customer_id) AS customers,
SUM(net_revenue_bdt) AS revenue,
SUM(net_revenue_bdt) / NULLIF(SUM(marketing_cost_bdt),0) AS roas
FROM customer_value
GROUP BY acquisition_channel; Compares acquisition quality, not just volume.
Shift budget toward channels with durable value, while remembering attribution model limitations.
Running Totals, MTD & YTD
How is performance accumulating through the current period?
Leadership wants daily sales plus month-to-date progress against target.
SQL patternShow example query+
WITH daily AS (
SELECT order_date::date AS day, SUM(net_revenue_bdt) AS revenue
FROM orders GROUP BY 1
)
SELECT day, revenue,
SUM(revenue) OVER (PARTITION BY DATE_TRUNC('month', day) ORDER BY day) AS mtd_revenue,
SUM(revenue) OVER (PARTITION BY DATE_TRUNC('year', day) ORDER BY day) AS ytd_revenue
FROM daily; Makes pace and cumulative performance visible without losing the daily grain.
Compare MTD pace with target and prior periods before reacting to a single weak day.
Price & Discount Impact
How do price or promotion changes relate to units, revenue and margin?
A category raises price while a competitor runs discounts. Sales volume falls.
SQL patternShow example query+
SELECT price_band, discount_flag,
COUNT(*) AS units,
AVG(unit_price_bdt) AS avg_price,
SUM(revenue_bdt) AS revenue,
SUM(margin_bdt) AS margin
FROM sales
GROUP BY 1, 2; Shows how commercial outcomes differ across price/discount conditions.
Use this descriptively first; true price elasticity needs stronger causal design than a simple grouped SQL result.
Measure activation, adoption, experiments and unexpected change.
Time-to-Event Analysis
How long does it take users to reach an important milestone?
A fintech app wants to shorten time from registration to first successful transaction.
SQL patternShow example query+
SELECT user_id,
MIN(CASE WHEN event_name='signup' THEN event_time END) AS signup_time,
MIN(CASE WHEN event_name='purchase' THEN event_time END) AS first_purchase_time,
MIN(CASE WHEN event_name='purchase' THEN event_time END)
- MIN(CASE WHEN event_name='signup' THEN event_time END) AS time_to_purchase
FROM events
GROUP BY user_id; Measures activation speed and identifies users stuck before value realization.
Segment slow activators by platform, channel or onboarding step to find friction.
Feature Adoption & Engagement
How many eligible users actually use a feature?
A new saved-search feature launched but product needs to know whether customers discovered it.
SQL patternShow example query+
SELECT
COUNT(DISTINCT CASE WHEN event_name='saved_search_used' THEN user_id END) AS adopters,
COUNT(DISTINCT user_id) AS active_users,
1.0 * COUNT(DISTINCT CASE WHEN event_name='saved_search_used' THEN user_id END)
/ NULLIF(COUNT(DISTINCT user_id),0) AS adoption_rate
FROM events
WHERE event_date >= CURRENT_DATE - INTERVAL '30 days'; Separates feature availability from real behavior.
Low adoption may require discovery improvements; high adoption with low retention may indicate limited ongoing value.
A/B Testing Analysis
Did the variant outperform control on the agreed outcome?
A checkout experiment changes payment ordering. Compare conversion and guardrail metrics by assigned group.
SQL patternShow example query+
SELECT experiment_group,
COUNT(DISTINCT user_id) AS users,
AVG(CASE WHEN converted THEN 1.0 ELSE 0 END) AS conversion_rate,
AVG(order_value_bdt) AS avg_order_value
FROM experiment_users
GROUP BY experiment_group; SQL produces experiment aggregates and integrity checks used before statistical inference.
Do not declare a winner from raw uplift alone—check assignment integrity, uncertainty and guardrails.
Anomaly Detection
Is today unusually different from its recent baseline?
Transactions suddenly drop after a release. Compare actual volume with a rolling baseline.
SQL patternShow example query+
WITH daily AS (
SELECT event_date, COUNT(*) AS transactions
FROM payments GROUP BY event_date
)
SELECT event_date, transactions,
AVG(transactions) OVER (ORDER BY event_date ROWS BETWEEN 7 PRECEDING AND 1 PRECEDING) AS trailing_avg,
transactions - AVG(transactions) OVER (ORDER BY event_date ROWS BETWEEN 7 PRECEDING AND 1 PRECEDING) AS delta
FROM daily; Creates a simple monitoring baseline for sudden spikes or drops.
Treat a large deviation as an investigation trigger, not proof of root cause.
Turn operational data into early-warning decisions.
Inventory Turnover & Stock Risk
Which products are likely to run out or remain overstocked?
A fast-moving SKU has four days of inventory left but supplier lead time is nine days.
SQL patternShow example query+
SELECT product_id,
current_stock,
AVG(daily_units_sold) AS avg_daily_sales,
current_stock / NULLIF(AVG(daily_units_sold),0) AS days_of_cover
FROM inventory_daily
WHERE snapshot_date >= CURRENT_DATE - INTERVAL '14 days'
GROUP BY product_id, current_stock; Combines stock with sales velocity to prioritize replenishment.
Escalate SKUs where days of cover is below supplier lead time; reduce purchasing for slow-moving excess stock.
Fraud & Risk Detection
Which transaction patterns are unusual enough to review?
One account places several high-value orders from multiple locations in a short period.
SQL patternShow example query+
SELECT customer_id,
COUNT(*) AS orders_1h,
COUNT(DISTINCT district) AS districts_1h,
SUM(amount_bdt) AS value_1h
FROM transactions
WHERE transaction_time >= CURRENT_TIMESTAMP - INTERVAL '1 hour'
GROUP BY customer_id
HAVING COUNT(*) >= 5
OR COUNT(DISTINCT district) >= 3; Rules-based SQL is useful for surfacing suspicious behavior for further review.
Flag for investigation or step-up verification; do not treat a heuristic flag as proof of fraud.
SQL can calculate a pattern without proving the story.
Retention, churn and conversion are denominator problems before they are SQL problems.
Do not let event, item or payment rows multiply customer- or order-level measures.
A number is rarely meaningful without prior period, control group, target or historical range.
Price, discounts, campaigns and feature usage often have selection effects. SQL alone cannot remove them.
Check nulls, late events, refunds, cancelled orders, duplicate identities and incomplete tracking.
A useful analysis ends with what the team should investigate, change, test or monitor next.
Patterns turn SQL syntax into business reasoning.
When a stakeholder asks a new question, first ask whether it is really a familiar pattern—cohort, retention, funnel, segmentation, value, time-to-event, experiment, anomaly, inventory or risk. Then adapt the pattern to the company’s actual data model and metric definitions.