Sample dataset · CC0

Sales transactions that add up.

Two years of daily orders, five regions, three channels and eight products. Revenue is exactly units times unit price on every row, so any total you compute can be checked against any other total you compute.

7 columns · 100 or 1,000 rows as a file · up to 1,000,000 rows generated here · CSV, JSON, JSONL, Excel, Parquet

Take a file

Two sizes ship as files. The 100-row file is for a screenshot or a unit test; the 1,000-row file is the one to open in a dashboard, because it has enough rows per month for a trend to be visible.

Or build a big one right here

Ten thousand rows is a realistic month of a small business. A hundred thousand is where naive spreadsheet formulas start to hurt. A million is where you find out whether your tool streams or loads. All three are built here, in this tab, from the same generator that produced the files above.

The first eight rows

These are the first eight rows of the 1,000-row file, exactly as they appear in it.

dateregionproductchannelunitsunit_pricerevenue
2024-07-01LATAMDesk LampRetail3664.222311.92
2024-07-02EMEAHD WebcamPartner2826.17732.76
2024-07-02North AmericaDesk LampRetail1964.221220.18
2024-07-03EMEAMechanical KeyboardOnline38210.437996.34
2024-07-04LATAMPortable SSDOnline341.29123.87
2024-07-05EMEALaptop StandPartner1614.78236.48
2024-07-05North AmericaMechanical KeyboardRetail31210.436523.33
2024-07-06North AmericaLaptop StandOnline1914.78280.82

Seven columns, and what each one holds

Column Type What it holds Example
date date Transaction date, ISO 8601, ascending through the file. 2024-07-01
region text One of five sales regions. LATAM
product text One of eight products, drawn with an uneven popularity curve. Desk Lamp
channel text Online, Retail or Partner. Retail
units integer Units sold on the line, 1 to 40. 36
unit_price decimal Price per unit in USD, fixed per product. 64.22
revenue decimal units times unit_price, rounded to cents. The arithmetic holds on every row. 2311.92

What it models

This is a transaction log, not a summary. One row is one line on one order: a date, where it was sold, what was sold, through which channel, how many units and at what price. There is no customer on it and no order id, because the point of the file is aggregation rather than joining. If you want the joining version, that is the orders dataset.

The date column spans 2024-07-01 to 2026-06-30 at every size. A 100-row file puts roughly one row a week across those two years; the million-row file puts about 1,370 rows a day across the same two years. That is on purpose, so that a chart built against the small file and a chart built against the big one have the same shape and only differ in density.

Product popularity is uneven. The draw is skewed rather than flat, so a bar chart of units by product has a real slope to it instead of eight bars of the same height, which is what makes most generated sales data look obviously fake at a glance.

The arithmetic that holds

Unit price is fixed per product across the whole file, so grouping by product and averaging unit_price returns exactly the price, not a smear. Revenue is units multiplied by unit_price, rounded to cents, on every single row, which means SUM(revenue) and SUM(units * unit_price) agree to the penny at any grouping you choose.

That sounds obvious until you try it on most sample sales files, where revenue is drawn independently and the two totals differ by a few percent. Ours is checked by a test that walks all 1,000 rows and fails the build if any row disagrees, because a teaching file whose arithmetic is wrong teaches the wrong lesson.

Where it gets interesting

Three grouping columns of different cardinality make this a good pivot subject: five regions, three channels and eight products. Region by channel is a 15-cell grid that fits on a slide. Product by month over two years is a 192-cell grid that does not, which is the point at which people discover whether their pivot tool can scroll.

It is also a reasonable performance yardstick. At a million rows the CSV is around 55 MB, which is small enough to open in a browser tab and large enough that a spreadsheet will refuse or truncate. If you are comparing tools, generate the million-row file once and hand the same bytes to each of them.

What people use it for

  • A first dashboard: revenue over time, revenue by region, units by product.
  • Pivot table practice, with three grouping columns of deliberately different cardinality.
  • Checking that a tool's aggregation and your own arithmetic agree, because here they must.
  • Performance comparisons, using the same million rows in every tool.
  • SQL teaching: GROUP BY, SUM, ORDER BY and date truncation all have something honest to work on.

License, and the people in it

This dataset is dedicated to the public domain under CC0 1.0. Put it in a course, a paid product, a test suite, a bug report, a screenshot, a conference talk or a book. There is nothing to ask for, nothing to sign and no attribution required. A link back is welcome and is not a condition.

Nothing in this file describes a real person. The names are drawn from a fixed pool, the addresses are cities rather than street addresses, and every email address ends in example.com, the domain RFC 2606 reserves so that test mail can never be delivered to anybody. There is no personal information here to anonymize and none to leak.

Questions people ask about this file

Does revenue really equal units times unit price on every row?

Yes, and it is checked. A test walks every row of the 1,000-row file and compares revenue against units multiplied by unit_price to two decimal places; if any row disagreed the build would fail. Unit price is also fixed per product across the file, so an average of unit_price grouped by product returns the exact price rather than an average of noise.

Are the dates sequential, and do they cover the same period at every size?

The date column ascends through the file and every size covers 2024-07-01 to 2026-06-30. That is why the generator needs to know the row count: it spreads the rows evenly across the fixed window rather than starting at day one and running until it runs out. A 100-row file therefore has about one row a week and a million-row file has about 1,370 rows a day, over the same two years.

Is the 1,000-row file the first 1,000 rows of the million-row file?

No, and that is deliberate. Because every size covers the same date window, the rows are different at every size. What is guaranteed is that a given size is always identical: sales-transactions-1000.csv is the same bytes for everybody, and pressing "100k rows" here gives you the same bytes as anybody else pressing it.

Can I use this in a course or a commercial product?

Yes. It is CC0 1.0, which is a public domain dedication rather than a license with conditions. Put it in course material, a paid product, a book, a conference talk or a test suite, with or without attribution, and there is nothing to ask for and nothing to sign.

Why is there no customer or order id?

Because this file is for aggregation and the joins would be dead weight. If you want keys that resolve, use the orders dataset instead: its customer_id points at a real row in customers, its sku points at a real row in products, and its unit_price matches the catalogue price for that SKU, so a three-way join reconciles exactly.