Back to case files
Case 022026 · Sales analytics

Is the growth real demand, or is it discounting?

A full-year gross-to-net analysis of a multi-channel Meru supermarket, tested channel by channel and segment by segment.

SQLDeepnoteSales analytics

At a glance

Gross sales (2025)
KES 267.8M
Discount given
KES 12.9M
Blended discount rate
4.82%
Orders
8,010

The verdict

Growth is demand-driven at the aggregate level — a 4.82% blended discount rate, with channel rank order unchanged once discounts are subtracted. The real cost is concentrated in two places: the Delivery channel (7.89%, flat regardless of order size) and High Value customers (5.52%).

Discounting touches ~79% of orders but buys only a 5–6% lift in order size. The two largest revenue combinations — B2B + Loyal and B2B + Regular — are healthy and need no intervention.

Stage 1

Business context

Executive summary

Mimea FoodMart's leadership could see revenue growing but could not say with confidence whether that growth reflected genuine customer demand or was being manufactured through discounting. As the analyst brought in to investigate, I was asked to answer that question with evidence, and to determine whether the answer changed depending on sales channel or customer segment.

Company overview

Mimea FoodMart is a supermarket operating in Meru County, Kenya. It serves five distinct customer types — households, restaurants, retailers, institutions, and small businesses — through five sales channels: Physical Store, WhatsApp, Phone Order, Delivery, and B2B.

Industry context

Mimea operates in Kenya's retail and FMCG grocery space, a sector where multi-channel selling (in-store, mobile-order, and business-to-business supply) is increasingly common, and where discounting is a routine competitive tool. The tension this creates — discounting can win volume, but it can also quietly erode realized revenue — is not unique to Mimea, but it is rarely quantified rigorously at the channel-and-segment level rather than as a single blended number.

Business model

Mimea generates revenue by selling groceries, fresh produce, beverages, household goods, and other FMCG products across its five channels, at prices that can be discounted depending on channel, customer segment, and negotiated terms — particularly for B2B and institutional buyers.

Stakeholders

Finance, who first flagged the discrepancy between strong gross sales in some channels and unclear realized revenue. Sales and marketing, who own discount policy and were the intended audience for the final recommendations. Store and channel operations, who would need to act on any findings specific to a channel like Delivery.

Current situation

Revenue is growing year over year, which reads as a positive signal in isolation. However, no one on the team had broken that growth down by what portion is genuine gross demand versus what portion is being given away as discount before it becomes net revenue.

Problem statement

Management does not know whether Mimea's sales growth is demand-driven or discount-driven, and does not know whether the answer to that question differs meaningfully by sales channel or customer segment.

Why analysis matters

Without this breakdown, sales and marketing risk two opposite mistakes: cutting discounts broadly and suppressing genuine demand, or leaving a structural discount problem in place because it's hidden inside a healthy-looking blended average.

Assumptions

The following are assumptions made to construct a realistic, internally consistent synthetic dataset for this project, not facts about a real business.

  • 1Discount depth was assumed to be driven primarily by two factors: sales channel and customer segment, layered together, rather than by product category or random chance.
  • 2Customer segment was assumed to correlate with account tenure — newer customers registered more recently, longer-tenured customers assigned to Loyal or High Value segments — as a realistic proxy for how segmentation typically develops in a real loyalty structure.
  • 3Certain customer types were assumed to prefer certain channels (e.g., Institutions and Retailers skewing toward B2B, Households skewing toward Physical Store), consistent with realistic B2B versus retail purchasing behavior.
  • 4No product cost or margin data was assumed or included; this project is scoped to gross-to-net discount economics only, not profitability.

Expected business value

A clear, evidence-based answer to where discounting is working as intended, where it is a structural cost with no volume benefit, and which parts of the business need no intervention at all — allowing sales and marketing to act precisely rather than broadly.

Stage 2

Data understanding

Data overview

The dataset is a synthetic, star-schema sales dataset covering the full 2025 calendar year, built specifically to support this analysis with deliberately embedded (not random) discount patterns.

Data sources

All data was synthetically generated in Python to represent a fictional but operationally realistic supermarket, since no real Mimea FoodMart dataset exists. This is a deliberate portfolio-project design choice, not a data collection process from a live business.

Assumption: for the purposes of this case study, the data is treated as if it were exported from Mimea's point-of-sale and order management systems across all five channels, covering every transaction in 2025.

Data pipeline

Five CSV tables — sales.csv, customers.csv, products.csv, channels.csv, dates.csv — generated via a Python script and loaded directly into a DeepNote SQL notebook for querying.

Data dictionary — sales.csv (fact table)

One row = one product line within one order.

ColumnDescription
sales_idUnique line-item identifier
order_idOrder/transaction identifier
date_idLinks to dates.csv
customer_idLinks to customers.csv
product_idLinks to products.csv
channel_idLinks to channels.csv
quantityUnits purchased on this line
unit_pricePrice per unit before discount
discount_pctDiscount percentage applied to this line
discount_amountDiscount value in KES
gross_salesquantity × unit_price
net_salesgross_sales − discount_amount

customers.csv

customer_id, customer_name, customer_type (Household, Restaurant, Retailer, Institution, Small Business), customer_segment (New, Regular, Loyal, High Value), location, registration_date

products.csv

product_id, product_name, category, subcategory, brand, standard_price

channels.csv

channel_id, channel_name (Physical Store, WhatsApp, Phone Order, Delivery, B2B)

dates.csv

date_id, full_date, day, month, month_name, quarter, year, day_of_week

Data quality assessment

Validated directly in the analysis journey (Step 0) via six checks: row counts, referential integrity, duplicate keys, arithmetic consistency (gross − discount = net), date coverage, and nulls in key columns. All six checks returned clean with zero exceptions — so no cleaning was required.

Limitations

The dataset contains no product cost or margin field, so this analysis is scoped to gross sales, discount, and net sales only; it cannot speak to profitability. It also contains no historical data prior to 2025, so no year-over-year growth comparison is possible within this dataset alone — the "growth" framing in the business question is addressed through channel and segment discount economics, not a multi-year trend line.

Analytical readiness was confirmed following the Step 0 validation, with no unresolved data quality issues carried forward.

Stage 3

Business objectives & KPIs

Business goals

Determine whether Mimea's sales growth is demand-driven or discount-driven, and identify any channel or segment where discounting is a cost without a corresponding business benefit.

Stakeholder questions

  1. 1Which channels generate the most gross sales, and does that ranking hold once discounts are subtracted?
  2. 2Which channels and segments carry the highest discount rates, and is that a channel behavior or a customer behavior?
  3. 3Are High Value customers the strongest net revenue contributors?
  4. 4Do discounted orders come with meaningfully more volume?
  5. 5Which product categories lean hardest on discounting?

Analytical questions

  1. 1What is the blended, whole-business discount rate?
  2. 2How does gross sales, net sales, and discount rate vary by channel?
  3. 3How does gross sales, net sales, and discount rate vary by customer segment?
  4. 4Does the channel effect or the segment effect explain discount variation, or both independently?
  5. 5Do discounted orders carry meaningfully higher volume than full-price orders?
  6. 6Does order size explain channel-level discount rate differences?
  7. 7Which product categories are most dependent on discounting?

Success metric

A channel or segment is flagged as a genuine concern only if it shows an elevated discount rate and no corresponding lift in order size or volume — discount rate alone is not treated as sufficient evidence of a problem.

KPI definitions

KPIWhy it mattersHow it's calculated
Blended discount rateWhole-business benchmark every channel/segment is measured againsttotal discount ÷ total gross sales
Channel discount rateDetects channel-specific discount dependencydiscount ÷ gross sales, grouped by channel
Segment discount rateDetects customer-specific discount dependencydiscount ÷ gross sales, grouped by segment
Net sales contribution %Identifies which channel/segment actually drives realized revenue, not just gross activitynet sales ÷ total net sales
Avg order value (net)Measures realized transaction value after discountingnet sales ÷ distinct order count
Order size by discount statusTests whether discounting is buying volumeavg units/gross value, discounted vs. full-price orders

Analytical plan

Validate data, establish a whole-business baseline, break down by channel, break down by segment, cross-tabulate channel and segment to isolate real effects from confounds, test order size against discounting, test category dependency, then synthesize into a single answer with targeted recommendations.

Stage 4

Analysis journey

Analysis workflow

I treated this as one business question tested through seven layered SQL queries rather than seven unrelated ones — each step either confirmed or complicated the step before it, and I didn't accept a finding until I'd checked whether a simpler explanation (customer mix, order size) could account for it instead.

Step 0 — Data validation

Before trusting any business number, I confirmed the dataset itself was reliable.

Step 0 — six validation checks
-- Row counts
select count(*) as sales_rows from sales.csv;
select count(*) as customer_rows from customers.csv;
select count(*) as product_rows from products.csv;
select count(*) as channel_rows from channels.csv;
select count(*) as date_rows from dates.csv;

-- Referential integrity
select count(*) as orphaned_customer_rows
from sales.csv s
left join customers.csv c on s.customer_id = c.customer_id
where c.customer_id is null;

select count(*) as orphaned_product_rows
from sales.csv s
left join products.csv p on s.product_id = p.product_id
where p.product_id is null;

select count(*) as orphaned_channel_rows
from sales.csv s
left join channels.csv ch on s.channel_id = ch.channel_id
where ch.channel_id is null;

-- Duplicate keys
select sales_id, count(*) as occurrences
from sales.csv
group by sales_id
having count(*) > 1;

-- Arithmetic consistency
select count(*) as arithmetic_mismatches
from sales.csv
where abs((gross_sales - discount_amount) - net_sales) > 0.01;

-- Date coverage
select min(full_date) as earliest_date, max(full_date) as latest_date, count(distinct full_date) as distinct_days
from dates.csv;

select count(distinct date_id) as distinct_sales_dates
from sales.csv;

-- Nulls in key columns
select
  sum(case when customer_id is null then 1 else 0 end) as null_customer,
  sum(case when product_id is null then 1 else 0 end) as null_product,
  sum(case when channel_id is null then 1 else 0 end) as null_channel,
  sum(case when discount_pct is null then 1 else 0 end) as null_discount_pct,
  sum(case when gross_sales is null then 1 else 0 end) as null_gross,
  sum(case when net_sales is null then 1 else 0 end) as null_net
from sales.csv;

Result: all checks returned clean — zero orphaned keys, zero duplicates, zero arithmetic mismatches, zero nulls, and full 2025 date coverage. The dataset required no cleanup and carries no data-quality caveats into the rest of the analysis.

1

Whole-business baseline

Step 1 — blended baseline
select
  sum(gross_sales) as total_gross_sales,
  sum(discount_amount) as total_discount,
  sum(net_sales) as total_net_sales,
  round(sum(discount_amount) / sum(gross_sales) * 100, 2) as blended_discount_rate_pct,
  count(distinct order_id) as total_orders,
  sum(quantity) as total_units_sold,
  round(sum(net_sales) / count(distinct order_id), 2) as avg_net_order_value
from sales.csv;

Result: KES 267,776,621 gross sales, KES 12,896,791 in discounts, KES 254,879,830 net, a 4.82% blended discount rate, 8,010 orders, 572,128 units sold, KES 31,820 average net order value. This became the benchmark every subsequent breakdown was measured against.

2

Channel performance, gross vs net

Step 2 — by channel
select
  ch.channel_name,
  sum(s.gross_sales) as gross_sales,
  sum(s.discount_amount) as discount_amount,
  sum(s.net_sales) as net_sales,
  round(sum(s.discount_amount) / sum(s.gross_sales) * 100, 2) as discount_rate_pct,
  round(sum(s.net_sales) / (select sum(net_sales) from sales.csv) * 100, 2) as pct_of_total_net_sales,
  count(distinct s.order_id) as orders,
  round(sum(s.net_sales) / count(distinct s.order_id), 2) as avg_net_order_value
from sales.csv s
join channels.csv ch on s.channel_id = ch.channel_id
group by ch.channel_name
order by net_sales desc;

Result: Channel ranking by net sales matched the ranking by gross sales exactly (B2B, WhatsApp, Phone Order, Delivery, Physical Store) — no channel lost rank once discounts were applied. But Delivery's discount rate, 7.89%, stood nearly double every other channel; Physical Store sat lowest at 2.27%.

3

Segment performance, gross vs net

Step 3 — by segment
select
  c.customer_segment,
  sum(s.gross_sales) as gross_sales,
  sum(s.discount_amount) as discount_amount,
  sum(s.net_sales) as net_sales,
  round(sum(s.discount_amount) / sum(s.gross_sales) * 100, 2) as discount_rate_pct,
  round(sum(s.net_sales) / (select sum(net_sales) from sales.csv) * 100, 2) as pct_of_total_net_sales,
  count(distinct s.order_id) as orders,
  round(sum(s.net_sales) / count(distinct s.order_id), 2) as avg_net_order_value
from sales.csv s
join customers.csv c on s.customer_id = c.customer_id
group by c.customer_segment
order by net_sales desc;

Result: Discount rate rose in a clean step pattern from New (4.17%) to High Value (5.52%). High Value carried the highest average order value (KES 44,883) but was not the top segment by total net sales contribution — Regular held that position (30.99%) on order volume alone. This raised the question of whether the segment effect was actually a channel effect in disguise.

4

Channel and segment combined

Step 4 — channel × segment
select
  ch.channel_name,
  c.customer_segment,
  sum(s.gross_sales) as gross_sales,
  sum(s.discount_amount) as discount_amount,
  round(sum(s.discount_amount) / sum(s.gross_sales) * 100, 2) as discount_rate_pct,
  count(distinct s.order_id) as orders
from sales.csv s
join channels.csv ch on s.channel_id = ch.channel_id
join customers.csv c on s.customer_id = c.customer_id
group by ch.channel_name, c.customer_segment
order by ch.channel_name, discount_rate_pct desc;

Result: This isolated both effects as real and independent. Every segment discounted higher on Delivery than on any other channel it used — even New customers hit 6.95% on Delivery, nearly double their Physical Store rate. The segment gradient (High Value > Loyal > Regular > New) held inside every channel. Delivery + High Value produced the single highest combination in the dataset (8.75%); Physical Store + New produced the lowest (1.85%) — a 4.7x spread.

Mistake caught & corrected

Order-level double-counting
Step 5, first attempt (incorrect)
select
  case when discount_amount > 0 then 'Discounted' else 'Full Price' end as order_type,
  count(distinct order_id) as orders,
  round(avg(quantity), 2) as avg_units_per_line,
  round(sum(gross_sales) / count(distinct order_id), 2) as avg_gross_order_value
from sales.csv
group by case when discount_amount > 0 then 'Discounted' else 'Full Price' end;

This returned 6,295 "Discounted" orders and 3,538 "Full Price" orders — summing to 9,833, against a known total of 8,010 distinct orders from Step 1. The bug: classification was happening at the line level, not the order level, so any order containing both discounted and full-price lines was counted in both buckets, and avg_gross_order_value was averaging over a partial, mismatched set of lines rather than whole orders.

Corrected version
with order_level as (
  select
    order_id,
    sum(gross_sales) as order_gross_sales,
    sum(discount_amount) as order_discount_amount,
    sum(quantity) as order_units
  from sales.csv
  group by order_id
)
select
  case when order_discount_amount > 0 then 'Discounted' else 'Full Price' end as order_type,
  count(*) as orders,
  round(avg(order_units), 2) as avg_units_per_order,
  round(avg(order_gross_sales), 2) as avg_gross_order_value
from order_level
group by case when order_discount_amount > 0 then 'Discounted' else 'Full Price' end;

Fixed by aggregating to one row per order first, then classifying. Corrected totals reconciled exactly: 6,295 + 1,715 = 8,010. Corrected result: discounted orders averaged only 5–6% more in units (72.31 vs. 68.18) and gross value (KES 33,767 vs. KES 32,195) than full-price orders — a far smaller effect than the broken query implied, and a materially different conclusion (discounting is not driving meaningful volume lift).

6

Category-level discount dependency

Step 6 — by category
select
  p.category,
  sum(s.gross_sales) as gross_sales,
  sum(s.discount_amount) as discount_amount,
  sum(s.net_sales) as net_sales,
  round(sum(s.discount_amount) / sum(s.gross_sales) * 100, 2) as discount_rate_pct,
  round(sum(case when s.discount_amount > 0 then s.gross_sales else 0 end) / sum(s.gross_sales) * 100, 2) as pct_gross_sales_discounted
from sales.csv s
join products.csv p on s.product_id = p.product_id
group by p.category
order by discount_rate_pct desc;

Result: every category fell within a 4.69%–4.97% band — a flat result that ruled out merchandising as a discount driver entirely. Discount exposure is behavioral (channel and customer), not product-driven.

7

Consolidated cross-tab and the order-size challenge

Step 7 — consolidated cross-tab
select
  ch.channel_name,
  c.customer_segment,
  sum(s.gross_sales) as gross_sales,
  sum(s.discount_amount) as discount_amount,
  sum(s.net_sales) as net_sales,
  round(sum(s.discount_amount) / sum(s.gross_sales) * 100, 2) as discount_rate_pct,
  round(sum(s.net_sales) / (select sum(net_sales) from sales.csv) * 100, 2) as pct_of_total_net_sales,
  count(distinct s.order_id) as orders
from sales.csv s
join channels.csv ch on s.channel_id = ch.channel_id
join customers.csv c on s.customer_id = c.customer_id
group by ch.channel_name, c.customer_segment
order by pct_of_total_net_sales desc;

Result: B2B + Loyal (14.27%) and B2B + Regular (14.23%) are the two largest revenue combinations, both near the blended discount rate. Delivery + High Value, the worst discount economics in the dataset, is only 2.35% of total net sales — real, but small.

Before concluding Delivery's rate was a channel policy issue, I tested whether it was simply a function of order size:

Step 7 — order size by channel
with order_level as (
  select
    s.order_id,
    ch.channel_name,
    sum(s.gross_sales) as order_gross,
    sum(s.discount_amount) as order_discount,
    sum(s.quantity) as order_units
  from sales.csv s
  join channels.csv ch on s.channel_id = ch.channel_id
  group by s.order_id, ch.channel_name
)
select
  channel_name,
  case
    when order_units < 20 then 'Small (<20 units)'
    when order_units < 50 then 'Medium (20-49 units)'
    when order_units < 100 then 'Large (50-99 units)'
    else 'Very Large (100+ units)'
  end as order_size_bucket,
  count(*) as orders,
  round(avg(order_units), 2) as avg_units_in_bucket,
  round(sum(order_discount) / sum(order_gross) * 100, 2) as discount_rate_pct
from order_level
group by channel_name, order_size_bucket
order by channel_name, avg_units_in_bucket;

Result: ruled order size out completely. Delivery's smallest orders (avg. 6.07 units) discounted at 7.90%, statistically identical to its largest orders (148.27 units) at 7.96%. Every channel showed the same flat pattern internally. Delivery's discount is a fixed, structural cost of the channel, not a volume-based incentive.

Key findings

  1. 1Growth is demand-driven at the aggregate level — the 4.82% blended rate is modest, and channel rank order is unaffected by discounting.
  2. 2Delivery carries a flat, structural 7.89% discount rate, unrelated to order size, roughly double any other channel.
  3. 3High Value customers discount hardest on every channel, including the otherwise disciplined Physical Store.
  4. 4Discounting touches ~79% of orders but buys only a 5–6% size lift — it functions as a routine cost, not a volume lever.
  5. 5Product category has no meaningful effect on discount rate — the driver is entirely behavioral (channel/customer), not merchandising.

Lessons learned

Classifying at the line level instead of the order level silently double-counted orders and understated the real finding — a reminder to always aggregate to the correct grain before classifying, not after. It's also the second time in this portfolio series that an aggregate-before-join-style error has surfaced, which suggests it's worth building a standing checklist step for it rather than re-discovering it each project.

Results

KPI summary

KPIValue
Total gross sales (2025)KES 267,776,621
Total discount givenKES 12,896,791
Total net salesKES 254,879,830
Blended discount rate4.82%
Total orders8,010
Total units sold572,128
Average net order valueKES 31,820
Delivery discount rate7.89%
Physical Store discount rate (lowest)2.27%
High Value segment discount rate (highest)5.52%
New segment discount rate (lowest)4.17%
Delivery + High Value discount rate (worst combination)8.75%
Physical Store + New discount rate (best combination)1.85%
B2B + Loyal, share of total net sales14.27%
B2B + Regular, share of total net sales14.23%
Delivery + High Value, share of total net sales2.35%
Avg order size lift, discounted vs. full-price orders~5–6%
Share of orders carrying any discount~79%

Stage 5

Business recommendations

Executive summary

At the aggregate level, Mimea FoodMart's growth is demand-driven, not discount-driven. However, a real and quantified discount cost is concentrated in two specific places — the Delivery channel and High Value customers — and that cost is not currently generating a meaningful volume return. The rest of the business, including its two largest revenue combinations, is healthy and requires no intervention.

Dashboard narrative

A dashboard built from this analysis should lead with the gross-to-net waterfall at the whole-business level, then allow drill-down by channel and segment side by side, since neither view alone tells the full story. An order-size-by-channel view should sit next to the discount-rate view specifically to preempt the question of whether high discount rates simply reflect bigger orders — for Mimea, they don't.

Business recommendations

1

Investigate the Delivery channel's discount mechanism before treating it as a marketing lever.

A flat 7.89% rate, unrelated to order size, suggests an operational default or absorbed cost rather than a deliberate pricing decision. Confirm the mechanism first; if discretionary, tighten toward the 4–5% range other channels operate in.

2

Test a reduction in High Value discount depth in a single channel before changing segment-wide policy.

High Value customers already show the highest average order value in the business, suggesting demand is not primarily discount-dependent.

3

Leave B2B + Loyal and B2B + Regular untouched.

These combinations carry over a quarter of total net sales and already sit close to the blended discount rate.

4

Do not redistribute recovered discount budget as higher discounts elsewhere.

Physical Store and New customers are already the most disciplined combinations; a targeted acquisition offer for New customers is a better use of any recovered spend.

Expected business impact

Tightening Delivery's discount rate could recover a meaningful share of its ~KES 2.34M annual discount spend with no expected volume loss, since the rate isn't correlated with order size. A phased High Value discount reduction could improve realized margin on the segment with the highest average order value without necessarily reducing order frequency. Neither change affects the two largest, healthiest revenue combinations.

Risks

This analysis measures discount rate and order size, not price elasticity. It's clear discounting isn't currently buying much extra order size, but that doesn't prove demand would hold if discounts were removed entirely. Recommendations are deliberately phased (single-channel test, mechanism confirmation before adjustment) to manage this risk rather than cutting broadly on an untested assumption.

Next steps

Confirm with operations/finance whether Delivery's discount is a genuine pricing decision or an absorbed cost. Run the single-channel High Value test over one full quarter before wider rollout. Exclude B2B + Loyal and B2B + Regular from any company-wide discount policy change.

Future analysis opportunities

Incorporating real product cost data would allow a genuine margin analysis rather than a discount-rate analysis. A price elasticity study on the Delivery and High Value combination, using a controlled discount reduction, would close the biggest open risk identified in this report.

Not sure if your growth is demand or discount?

Every finding tested against a simpler explanation before it becomes a recommendation.