Ecommerce storefront
A year of orders across five joined tables, with a real Q4 peak and totals that reconcile to the cent.
An online retailer's 2025: customers, a 300-SKU catalogue, orders, line items, and reviews. Every order total is exactly the sum of its own line items, so the joins and the arithmetic both hold when you check them. Demand rises into November and December because there are more orders, not because the orders got bigger, which is how real seasonality works.
49,192 rows across 5 tables, 656 KB zipped. Public domain (CC0), no signup, no attribution required.
What is in it
customer_id, full_name, email, city, state, country, signup_date, segment
112 signed up and never ordered
product_id, product_name, category, unit_price, unit_cost
every SKU name distinct
order_id, customer_id, order_date, status, channel, order_total
order_item_id, order_id, product_id, quantity, unit_price, line_total
review_id, product_id, customer_id, rating, review_text, review_date
What holds, and how it was checked
Each line was measured against these exact files rather than asserted. The same checks ship inside the zip as INTEGRITY.txt, so you can re-run them yourself.
- 0 orphaned foreign keys across all 5 relationships
- 0 orders dated before their customer signed up
- order_total equals the sum of its line items, exactly, for every order
- 0 products priced at or below cost (margins run 22% to 64%)
- Ratings are J-shaped (57% five-star, 7% one-star), not uniform
- Top 10% of customers place 29.5% of orders, a realistic Pareto tail
- 59% of prices end in .99, as real catalogues do
- Every city belongs to its country (London and Newcastle appear under two, correctly)
Questions it can answer
- Which category carries the best margin, and is it the one selling most?
- How much of revenue comes from the top 10% of customers?
- Do low-rated products actually get returned more often?
- What does the Q4 lift look like split by channel?
Make your own version
The zip includes schema.yaml, which is this dataset's shape and runs as-is. Change a row count, add a column, rename a table: every foreign key still resolves, because referential integrity is a guarantee here rather than something the generator happens to get right.
pip install misata misata generate --config schema.yaml --output-dir ./dataRead the docs
Other datasets
- Retail star schema
A dimensional model you can actually practise joins on: one fact table, four dimensions, 63,170 rows, and every join resolving.
- Machine degradation
100 machines monitored from commissioning to failure, with an exact remaining-useful-life label on every one of 23,118 readings.
- B2B SaaS subscription analytics
Accounts, seats, MRR, churn and support load, where company size actually drives the plan.

