Case study · SQL · Power BI

E-commerce Sales and Delivery Performance

Using SQL and Power BI to compare sales, seller performance and delivery reliability across Brazil.

Explore the interactive report

Use the four report pages and their filters to explore market geography, sales and assortment, the seller network, and delivery experience. Monetary values are in Brazilian reais (R$).

Open the report in a separate tab for a larger view, especially on a phone.

Portfolio projectOlist public dataset

The business question

A marketplace can grow its sales while customers in some regions still face slow deliveries or high freight charges. I used SQL and Power BI to bring commercial performance and customer experience into a single report, allowing readers to compare where demand comes from, which sellers contribute to it and how delivery performance varies.

What the data showed

Historical dataset, with all years, regions and states selected. Verified against the public report on 16 October 2026.

  • The Southeast generated 65.4% of customer revenue. Customers in this region accounted for R$8.65 million of R$13.22 million in delivered product sales. This makes it the largest customer market in the report.
  • The top ten sellers generated 13.3% of revenue. Together they contributed R$1.75 million, among 2,970 active sellers. Their share makes these sellers worth monitoring, while most revenue came from the wider network.
  • The Northeast had the highest regional late-delivery rate: 12.7%. This compares with 6.8% overall and 6.1% in the Southeast. It is a clear priority for investigating delivery performance.
  • Late orders received much lower review scores. Reviewed late orders averaged 2.27 out of 5, compared with 4.29 for on-time orders. The gap shows an association between delivery reliability and customer ratings, not proof of causation.

See the source values and calculations used for these findings. The figures here are a fixed snapshot; the embedded report responds to your filters.

Building a reliable analytical model

In MySQL, I extracted the raw CSV records into staging tables, cleaned text and numeric fields, and built analytical views. Item, payment and review records are summarised to one row per order before joining them to the order table. This prevents an order with several items or payments from multiplying the order-level totals.

Separate customer and seller geography dimensions distinguish where demand originates from where sellers are based. DAX measures calculate delivered revenue, average order value, active sellers and delivery performance within the selected context.

SQL and geographic data quality

The accompanying geography SQL script uses common table expressions and window functions to deduplicate postcode coordinates, calculate median locations and select a single state for each postcode. It also includes checks comparing customer counts before and after the geography join, helping detect joins that could multiply records.

The report uses a geography snapshot prepared from the source CSVs; the SQL script reproduces the same logic in MySQL.

SQL you can inspect

This shortened example uses the same CTE, join and delivery-flag logic as the order view. It totals the items first, then joins one result per order. The CASE expression marks delivered orders.

WITH item_summary AS (
    SELECT order_id,
           SUM(CAST(price AS DECIMAL(12,2))) AS item_revenue
    FROM raw_order_items
    GROUP BY order_id
)
SELECT o.order_id,
       COALESCE(i.item_revenue, 0) AS item_revenue,
       CASE WHEN o.order_status = 'delivered'
            THEN 1 ELSE 0 END AS delivered_flag
FROM raw_orders o
LEFT JOIN item_summary i ON o.order_id = i.order_id;
See the product cleaning query

This extract fills missing category names, removes unwanted whitespace and converts product weight from text to a decimal number.

SELECT p.product_id,
       TRIM(BOTH '\r' FROM COALESCE(
           t.product_category_name_english,
           p.product_category_name, 'unknown')) AS product_category,
       CAST(NULLIF(p.product_weight_g, '') AS DECIMAL(12,2))
           AS product_weight_g
FROM raw_products p
LEFT JOIN raw_category_translation t
    ON p.product_category_name = t.product_category_name;
See the postcode join check

The before and after customer counts should match. The final column counts customers without matching coordinates, so missing geography stays visible.

SELECT COUNT(*) AS customer_rows_before_join
FROM dim_customer;

SELECT COUNT(*) AS customer_rows_after_join,
       SUM(g.postcode IS NULL) AS customers_without_coordinates
FROM dim_customer c
LEFT JOIN vw_postcode_geography g
  ON LPAD(c.customer_zip_code_prefix, 5, '0') = g.postcode;

View the SQL project on GitHub

Four views of marketplace performance

  • Market Geography: compare customer revenue, regional demand and service performance across Brazil.
  • Sales & Assortment: explore monthly delivered merchandise revenue, leading categories and freight charged.
  • Seller Network: examine seller concentration, leading sellers and regional commercial contribution.
  • Delivery Experience: compare late deliveries, delivery times and review outcomes.

Decisions the report supports

The report gives a marketplace team a way to investigate whether commercially important regions also experience delivery problems, how dependent sales are on particular sellers, and where freight charges deserve closer review. These comparisons can guide follow-up analysis and operational prioritisation.

Limits of the analysis

This is a historical public dataset. Differences between regions, sellers or review groups describe associations and do not establish causes. Revenue is not profit, and customer freight charges are not the marketplace's delivery costs.

KPI definitions: what the numbers mean

KPIs are the main numbers used to track business performance. Here, sales, orders and customer counts cover successfully delivered orders. All amounts are in Brazilian reais (R$), and the numbers change with your report filters.

Sales

How much did we sell?

Revenue
The value of products that reached customers. Shipping charges are excluded.
No. of orders
How many orders were delivered. One order containing five products still counts as one order.
Average order value
How much customers spent on products per order, on average. For example, R$300 across two orders means R$150 per order.
Freight charges
The shipping fees charged to customers.
Freight %
Shipping charges compared with product value. For example, R$30 in shipping on R$300 of products is 10%.
Average freight per order
The average shipping fee per order. For example, R$30 across two orders means R$15 per order.

Customers & Sellers

Who contributed to those sales?

No. of customers
How many different customers received an order. A customer with three orders counts once.
States served
How many Brazilian states had customers who received orders.
Active sellers
How many different sellers had at least one delivered sale.
Revenue per seller
The average product revenue per active seller. For example, R$1,000 across ten sellers means R$100 per seller, even if some sold much more than others.

Delivery & Reviews

How well did we deliver?

Average delivery days
The average time taken to deliver orders. For example, deliveries taking eight and twelve days average ten days. Orders without a recorded duration are excluded.
Late-delivery rate
The percentage of orders arriving after the promised date. For example, eight late deliveries out of 100 means 8% were late. Only delivered orders with both dates recorded are included.
On-time rate
The percentage arriving on or before the promised date, using the same orders as the late-delivery rate. If 8% were late, 92% were on time.
Average review score
The average customer rating. Each reviewed order contributes one score; orders without reviews are excluded.
Low review share
The percentage of reviewed orders rated 2 or below. For example, 20 poorly rated orders out of 100 reviewed orders means 20%.

Examples explain the calculations; they are not results from this dataset.

When filtering by category or seller, order counts and freight figures cover only the selected items. One order may appear in several categories, so category order counts should not be added together.