Sample data

Two CSV tables, 1,198 subscriptions and 40,000 events, published so the SQL in the articles here has something real to run against. They are the tables the queries name: subscriptions and events.

One command reads them straight off the web, with nothing to download and no database to install:

duckdb -c "SELECT * FROM 'https://dataacademy.ai/data/subscriptions.csv' LIMIT 5"

To keep them around for a session, load both into tables first. Every query in the articles assumes these two names:

CREATE TABLE subscriptions AS
  SELECT * FROM 'https://dataacademy.ai/data/subscriptions.csv';
CREATE TABLE events AS
  SELECT * FROM 'https://dataacademy.ai/data/events.csv';

subscriptions

One row per subscription — 1,198 rows, 1,085 customers, 566 still running. Signups run from 2024-08-07 to 2026-07-31.

Column Type Meaning
subscription_id integer Primary key. One row per subscription.
customer_id integer The customer who holds it, and the join key to events. Not unique here: a customer who cancels and comes back gets a second row.
plan text starter, standard, pro or enterprise.
signed_up_at date The day the subscription started.
cancelled_at date The day it ended. Empty for the 566 subscriptions still running at the snapshot.
monthly_price decimal Fixed by plan: 12.00, 29.00, 79.00, 249.00.
country text Two-letter code. Constant for a given customer.
channel text How the subscription was won: organic, paid_search, referral, partner or outbound.

events

One row per product event — 40,000 rows across 8,597 sessions, 2024-08-07 to 2026-07-31. 2,493 of them are purchases, and their amounts add up to 187,350.

Column Type Meaning
event_id integer Primary key, ordered by time.
customer_id integer Always present in subscriptions.
occurred_at timestamp Second resolution. Never before the customer signed up, never after they cancelled.
event_type text login, view, export or purchase.
session_id integer Groups the events of one sitting. Events inside a session are minutes apart; sessions are hours or days apart.
amount decimal Set on purchase rows only, and always positive. Empty everywhere else.

What holds true

The data is invented, but it is consistent, which is the part that matters when a query is meant to teach something. Every customer_id in events exists in subscriptions. No event happens before its customer signed up or after they cancelled. Only purchases carry an amount, and no amount is negative. Each plan has one price.

It also behaves the way a subscription business does, which is what makes the answers worth reading. Signups follow a season: quiet in July and August, busy in September and January. Cancellations cluster in the first two months and then slow down. Bigger plans stay longer. A customer uses the product hardest in the weeks after signing up. A handful of customers generate a large share of the events, and about one in ten cancels and comes back later — which is why customer_id repeats in the subscriptions table.

A seeded Python script builds both files, so the same script always produces the same rows. Use the data for anything, with no attribution and no licence to read: it describes no real person and no real company.

Articles that run on it