Sample e-commerce database: 8 related tables as JSON, CSV and PostgreSQL
A fictional US-style online shop in 8 related tables: customers, orders, order items, payments and shipments, with prices in USD. Download it as JSON, CSV or a PostgreSQL script, in a small and a medium size. Amounts reconcile, every reference is valid, and the files never change.
Complete files: schema, seed scripts and everything in one JSON
Sample shop: schema for PostgreSQL (CREATE TABLE)Fictional
-- Sample shop (US flavour, USD): schema for PostgreSQL. All data is invented; money is stored in cents. -- License: CC0 1.0 Universal (https://creativecommons.org/publicdomain/zero/1.0/) …
Eight tables with primary and foreign keys and CHECK rules for tax rates, status and totals. Also loads in SQLite.
Sample shop (small): tables, columns and relationsFictional
Sample shop (small, US flavour): 8 tables, money in cents (USD) Relations …
Overview of the eight tables with row counts, columns and the rules of the data (12 customers, 24 orders).
Sample shop (small): schema and data as SQL (PostgreSQL)Fictional
-- Sample shop (small, US flavour, USD): schema and data for PostgreSQL. All data is invented. -- License: CC0 1.0 Universal (https://creativecommons.org/publicdomain/zero/1.0/) BEGIN; …
One transaction with CREATE TABLE and INSERT for every table, in foreign-key order. Amounts in cents (USD).
Sample shop (small): all tables in one JSON fileFictional
{ "categories": [ { …One object with an array per table, suited for seed scripts. Amounts in cents (USD), references valid.
Sample shop (medium): tables, columns and relationsFictional
Sample shop (medium, US flavour): 8 tables, money in cents (USD) Relations …
Overview of the eight tables with row counts, columns and the rules of the data (60 customers, 160 orders).
Sample shop (medium): schema and data as SQL (PostgreSQL)Fictional
-- Sample shop (medium, US flavour, USD): schema and data for PostgreSQL. All data is invented. -- License: CC0 1.0 Universal (https://creativecommons.org/publicdomain/zero/1.0/) BEGIN; …
One transaction with CREATE TABLE and INSERT for every table, in foreign-key order. Amounts in cents (USD).
Sample shop (medium): all tables in one JSON fileFictional
{ "categories": [ { …One object with an array per table, suited for seed scripts. Amounts in cents (USD), references valid.
Single tables as JSON and CSV (small and medium)
Sample shop (small): categories as JSONFictional
[ { "id": 1, …Invented shop (USD): amounts in cents, totals match the line items, references between the tables are valid.
Sample shop (small): categories as CSVFictional
id,name,slug 1,Office & Stationery,office-stationery 2,Household,household …
UTF-8, comma separated, empty cell = NULL. Amounts in cents (USD), references between the tables valid.
Sample shop (small): products as JSONFictional
[ { "id": "prd_001", …Invented shop (USD): amounts in cents, totals match the line items, references between the tables are valid.
Sample shop (small): products as CSVFictional
id,sku,name,category_id,price_net_cents,tax_rate,stock,active,created_at prd_001,SKU-0001,"Notebook A5, squared",1,420,7,109,true,2025-10-04T08:00:00Z prd_002,SKU-0002,"Ballpoint pens, 10 pack",1,599,7,49,true,2025-07-14T08:00:00Z …
UTF-8, comma separated, empty cell = NULL. Amounts in cents (USD), references between the tables valid.
Sample shop (small): customers as JSONFictional
[ { "id": "cus_0001", …Invented shop (USD): amounts in cents, totals match the line items, references between the tables are valid.
Sample shop (small): customers as CSVFictional
id,customer_number,salutation,first_name,last_name,email,phone,newsletter,created_at cus_0001,C-100001,ms,Emily,Lee,emily.lee.1@example.net,+1 310 555 0126,false,2026-03-06T08:00:00Z cus_0002,C-100002,ms,Ava,Davis,ava.davis.2@example.net,+1 …
UTF-8, comma separated, empty cell = NULL. Amounts in cents (USD), references between the tables valid.
Sample shop (small): addresses as JSONFictional
[ { "id": "adr_0001", …Invented shop (USD): amounts in cents, totals match the line items, references between the tables are valid.
Sample shop (small): addresses as CSVFictional
id,customer_id,type,street,house_number,postal_code,city,region,country adr_0001,cus_0001,billing,Prototype Place,8782,63248,Testburg,CA,US adr_0002,cus_0002,billing,Fixture Boulevard,8018,48426,Mockford,CO,US …
UTF-8, comma separated, empty cell = NULL. Amounts in cents (USD), references between the tables valid.
Sample shop (small): orders as JSONFictional
[ { "id": "ord_00001", …Invented shop (USD): amounts in cents, totals match the line items, references between the tables are valid.
Sample shop (small): orders as CSVFictional
id,order_number,customer_id,billing_address_id,shipping_address_id,status,ordered_at,shipping_cents,total_net_cents,total_tax_cents,total_gross_cents,currency ord_00001,O-2026-000001,cus_0010,adr_0013,adr_0013,delivered,2026-01-16T12:31:45Z …
UTF-8, comma separated, empty cell = NULL. Amounts in cents (USD), references between the tables valid.
Sample shop (small): order_items as JSONFictional
[ { "id": "itm_000001", …Invented shop (USD): amounts in cents, totals match the line items, references between the tables are valid.
Sample shop (small): order_items as CSVFictional
id,order_id,product_id,quantity,unit_price_net_cents,tax_rate,net_cents,tax_cents,gross_cents itm_000001,ord_00001,prd_024,1,1495,7,1495,105,1600 itm_000002,ord_00002,prd_017,1,1290,7,1290,90,1380 …
UTF-8, comma separated, empty cell = NULL. Amounts in cents (USD), references between the tables valid.
Sample shop (small): payments as JSONFictional
[ { "id": "pay_00001", …Invented shop (USD): amounts in cents, totals match the line items, references between the tables are valid.
Sample shop (small): payments as CSVFictional
id,order_id,method,status,amount_cents,card_last4,paid_at,refunded_at pay_00001,ord_00001,prepayment,paid,2199,,2026-01-17T12:31:45Z, pay_00002,ord_00002,prepayment,paid,3579,,2026-01-27T21:28:09Z, …
UTF-8, comma separated, empty cell = NULL. Amounts in cents (USD), references between the tables valid.
Sample shop (small): shipments as JSONFictional
[ { "id": "shp_00001", …Invented shop (USD): amounts in cents, totals match the line items, references between the tables are valid.
Sample shop (small): shipments as CSVFictional
id,order_id,carrier,tracking_number,shipped_at,delivered_at shp_00001,ord_00001,ExampleParcel,TEST-0001-3GB,2026-01-18T04:31:45Z,2026-01-21T04:31:45Z shp_00002,ord_00002,SampleLogistics,TEST-0002-17M,2026-01-28T01:28:09Z,2026-02-01T01:28:09 …
UTF-8, comma separated, empty cell = NULL. Amounts in cents (USD), references between the tables valid.
Sample shop (medium): categories as JSONFictional
[ { "id": 1, …Invented shop (USD): amounts in cents, totals match the line items, references between the tables are valid.
Sample shop (medium): categories as CSVFictional
id,name,slug 1,Office & Stationery,office-stationery 2,Household,household …
UTF-8, comma separated, empty cell = NULL. Amounts in cents (USD), references between the tables valid.
Sample shop (medium): products as JSONFictional
[ { "id": "prd_001", …Invented shop (USD): amounts in cents, totals match the line items, references between the tables are valid.
Sample shop (medium): products as CSVFictional
id,sku,name,category_id,price_net_cents,tax_rate,stock,active,created_at prd_001,SKU-0001,"Notebook A5, squared",1,420,7,18,true,2025-07-13T08:00:00Z prd_002,SKU-0002,"Ballpoint pens, 10 pack",1,599,7,49,true,2025-11-02T08:00:00Z …
UTF-8, comma separated, empty cell = NULL. Amounts in cents (USD), references between the tables valid.
Sample shop (medium): customers as JSONFictional
[ { "id": "cus_0001", …Invented shop (USD): amounts in cents, totals match the line items, references between the tables are valid.
Sample shop (medium): customers as CSVFictional
id,customer_number,salutation,first_name,last_name,email,phone,newsletter,created_at cus_0001,C-100001,ms,Chloe,Carter,chloe.carter.1@example.net,+1 310 555 0179,false,2026-03-31T13:47:35Z cus_0002,C-100002,ms,Amelia,Taylor,amelia.taylor.2@ …
UTF-8, comma separated, empty cell = NULL. Amounts in cents (USD), references between the tables valid.
Sample shop (medium): addresses as JSONFictional
[ { "id": "adr_0001", …Invented shop (USD): amounts in cents, totals match the line items, references between the tables are valid.
Sample shop (medium): addresses as CSVFictional
id,customer_id,type,street,house_number,postal_code,city,region,country adr_0001,cus_0001,billing,Sandbox Drive,9605,13706,Demoville,CO,US adr_0002,cus_0002,billing,Test Road,8802,62425,Mockford,OR,US …
UTF-8, comma separated, empty cell = NULL. Amounts in cents (USD), references between the tables valid.
Sample shop (medium): orders as JSONFictional
[ { "id": "ord_00001", …Invented shop (USD): amounts in cents, totals match the line items, references between the tables are valid.
Sample shop (medium): orders as CSVFictional
id,order_number,customer_id,billing_address_id,shipping_address_id,status,ordered_at,shipping_cents,total_net_cents,total_tax_cents,total_gross_cents,currency ord_00001,O-2026-000001,cus_0016,adr_0021,adr_0021,delivered,2026-01-05T23:59:52Z …
UTF-8, comma separated, empty cell = NULL. Amounts in cents (USD), references between the tables valid.
Sample shop (medium): order_items as JSONFictional
[ { "id": "itm_000001", …Invented shop (USD): amounts in cents, totals match the line items, references between the tables are valid.
Sample shop (medium): order_items as CSVFictional
id,order_id,product_id,quantity,unit_price_net_cents,tax_rate,net_cents,tax_cents,gross_cents itm_000001,ord_00001,prd_027,2,1190,0,2380,0,2380 itm_000002,ord_00001,prd_017,1,1290,7,1290,90,1380 …
UTF-8, comma separated, empty cell = NULL. Amounts in cents (USD), references between the tables valid.
Sample shop (medium): payments as JSONFictional
[ { "id": "pay_00001", …Invented shop (USD): amounts in cents, totals match the line items, references between the tables are valid.
Sample shop (medium): payments as CSVFictional
id,order_id,method,status,amount_cents,card_last4,paid_at,refunded_at pay_00001,ord_00001,debit_card,paid,4359,6748,2026-01-06T00:04:52Z, pay_00002,ord_00002,paypal,failed,6029,,, …
UTF-8, comma separated, empty cell = NULL. Amounts in cents (USD), references between the tables valid.
Sample shop (medium): shipments as JSONFictional
[ { "id": "shp_00001", …Invented shop (USD): amounts in cents, totals match the line items, references between the tables are valid.
Sample shop (medium): shipments as CSVFictional
id,order_id,carrier,tracking_number,shipped_at,delivered_at shp_00001,ord_00001,SampleLogistics,TEST-0001-1XG,2026-01-07T08:59:52Z,2026-01-10T08:59:52Z shp_00002,ord_00004,ExampleParcel,TEST-0004-6MW,2026-01-13T09:24:19Z,2026-01-14T09:24:19 …
UTF-8, comma separated, empty cell = NULL. Amounts in cents (USD), references between the tables valid.
What is in the data
Two sizes of the same shop. The small set (12 customers, 24 orders) is meant for reading and unit tests, the medium set (60 customers, 160 orders) for dashboards, pagination and joins. They are separate datasets, not prefixes of each other. In the files, net means before tax and gross means after tax.
| Table | Small | Medium | Purpose and rules |
|---|---|---|---|
categories | 6 | 6 | Product groups. Food is taxed at 0 %, everything else at 7 %. |
products | 29 | 29 | Prices are net (before tax), in cents. Some products are sold out (stock = 0) or inactive (active = false). |
customers | 12 | 60 | Invented people, e-mail only on example.* domains. phone can be NULL. The last customers never ordered. |
addresses | 16 | 80 | Every customer has a billing address, some also a separate shipping address. Street, city and state are invented and unrelated to the random ZIP code. |
orders | 24 | 160 | Totals = sum of the order items + shipping. shipping_cents is 599, or 0 from 75.00 USD of goods. Shipping is untaxed. |
order_items | 47 | 327 | Price and tax rate are the values at order time. gross = net + tax, net = quantity * unit price. Sales tax is added on top of the price: 0 % on food, 7 % on everything else. This is a fictional rule that does not follow any real state. |
payments | 24 | 152 | At most one payment per order. Cancelled orders without an instant payment method have none. Invoices can be open although the goods have shipped. card_last4 holds the last four digits of a card payment, nothing more. |
shipments | 15 | 137 | Only for shipped, delivered and refunded orders. delivered_at is NULL while the parcel is on its way. |
How the tables relate
categories 1 ── n products 1 ── n order_items n ── 1 orders customers 1 ── n addresses │ customers 1 ── n orders ─────────────────────────────┤ orders 1 ── 0..1 payments │ orders 1 ── 0..1 shipments ───────────────────────┘ orders.billing_address_id, orders.shipping_address_id -> addresses.id
Rules the data follows
- Money in cents. A line item has net = quantity × unit price, tax = round(net × rate / 100) and gross = net + tax.
- Tax and shipping. Sales tax is added on top of the price: 0 % on food, 7 % on everything else. This is a fictional rule that does not follow any real state. Shipping is 5.99 USD and untaxed, free from 75.00 USD of goods.
- Order totals are the sums of the line items plus shipping, and total gross = total net + total tax. A payment amount always equals the order total.
- Timelines make sense. Ordered, then paid, then shipped, then delivered. Invoice payments may arrive after shipping, and a refund comes after delivery. Everything lies before the fixed “today”.
- References are valid. Every foreign key points to an existing row, and an order's addresses belong to the order's customer.
- Edge cases are built in: sold-out and inactive products, a customer without a phone number, customers who never ordered, cancelled orders with and without a failed payment, refunds, and shipped orders whose invoice is still pending.
These rules are checked by automated tests, including a load of the generated SQL into a real database with foreign keys switched on.
Load it into PostgreSQL
Download the seed script of the size you want (it creates the tables and inserts the rows inside one transaction), then run:
createdb shop_demo psql shop_demo -f shop-us-small-seed.sql
If you already have your own schema, use the schema file as a reference and load the per-table CSV files with \copy, or insert the JSON from a script:
import { readFileSync } from 'node:fs'
const shop = JSON.parse(readFileSync('shop-us-small.json', 'utf8'))
for (const order of shop.orders) { /* insert with your ORM */ }Example queries
These run unchanged on PostgreSQL and SQLite and return rows on the medium set.
Revenue and order count per status
SELECT status, COUNT(*) AS orders, SUM(total_gross_cents) / 100.0 AS revenue FROM orders GROUP BY status ORDER BY revenue DESC;
Top products by net revenue
SELECT p.name, SUM(i.quantity) AS units, SUM(i.net_cents) / 100.0 AS net_revenue FROM order_items i JOIN products p ON p.id = i.product_id GROUP BY p.id, p.name ORDER BY net_revenue DESC LIMIT 5;
Shipped but not yet paid (open invoices)
SELECT o.order_number, c.email, o.total_gross_cents / 100.0 AS amount, o.ordered_at
FROM orders o
JOIN customers c ON c.id = o.customer_id
JOIN payments pay ON pay.order_id = o.id
WHERE pay.status = 'pending' AND o.status IN ('shipped', 'delivered')
ORDER BY o.ordered_at;Customers who never ordered
SELECT c.customer_number, c.email FROM customers c LEFT JOIN orders o ON o.customer_id = c.id WHERE o.id IS NULL;
Tax collected per tax rate
SELECT tax_rate, SUM(net_cents) / 100.0 AS net, SUM(tax_cents) / 100.0 AS tax FROM order_items GROUP BY tax_rate ORDER BY tax_rate;
License
The files on this page are generated from this site's own code and word lists and are released under CC0 1.0 Universal, a public domain dedication. You may copy, modify and use these files for any purpose, including commercial projects, without asking and without attribution. The files are provided as they are, without any warranty. All data is invented and must not be used to represent real people, accounts or transactions. The license covers these generated files only, not the text of this site.
Related
The test data edge cases page has deliberately broken versions of one order from this shop, one violated rule each. The German flavour of the same shop (EUR, VAT, SEPA payments with test IBANs created like those of the test IBAN generator) is in the German library: Beispiel-Shop-Datenbank (in German). Order numbers follow the idea behind the invoice number generator.
Frequently asked questions
Is any of this real data?
Why are amounts in cents?
Which sales tax rules does the data follow?
Is there a version with other currencies or VAT?
Can I load it into MySQL, SQLite or another database?
Does the data change over time?
Are there edge cases in the data?
Can I use the files in my own project?
Related tools
- Test Data Edge Cases: CSV, Unicode, JSON, Dates and API FixturesFixtures for the cases that break importers and validators: quoted CSV, Unicode traps, DST, rounding, API errors and broken relations.Testdaten · Dataset
- Test IBAN Generator: Fake IBANs with a Valid ChecksumTest IBANs with a valid checksum and a placeholder bank code instead of a real bank. For forms, demos and software tests.Banking & Steuern · Generator
- Invoice Number Generator: Formats and SequencesGenerate invoice numbers from your own pattern: combine year, month, day and a running number.Rechnungen · Generator
Sources and status
- PostgreSQL documentation: psql
- RFC 2606: reserved example domains (example.com, example.org, example.net)
- CC0 1.0 Universal (license of the generated files)
Content last reviewed: October 2026. Not legal or tax advice; the statements of the competent authorities prevail.