Sample dataset · CC0
Support tickets with honest clocks.
Ten columns of helpdesk export covering a year. Response times scale with priority the way an SLA makes them, resolution is never faster than first response, and satisfaction is blank for open tickets and for the third of customers who never answer the survey.
10 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
The 1,000-row file is a quarter of a small support team's volume. Its customer_id column points into the customers dataset, so ticket volume by plan tier is one join away.
| Format | Small | Standard |
|---|---|---|
| CSV | 100 rows (7.5 KB) | 1,000 rows (74.3 KB) |
| JSON | 100 rows (22.4 KB) | 1,000 rows (223.2 KB) |
| JSONL | 100 rows (22.1 KB) | 1,000 rows (220.3 KB) |
| Excel | 100 rows (20.3 KB) | 1,000 rows (137.1 KB) |
| Parquet | 100 rows (4.6 KB) | 1,000 rows (25.2 KB) |
A year at higher volume
Bigger sizes keep the same one-year window and the same priority mix, so the SLA distribution holds while the volume rises. A hundred thousand tickets is a useful size for testing whether a dashboard can bucket a long-tailed duration column.
The first eight rows
The first eight rows of the 1,000-row file. Look at the blank cells: they mean something specific.
| ticket_id | created_at | customer_id | channel | priority | category | first_response_min | resolution_min | status | satisfaction |
|---|---|---|---|---|---|---|---|---|---|
| TCK-000001 | 2025-07-01T00:00:00Z | 1175 | Chat | Urgent | Data import | 3 | 412 | closed | |
| TCK-000002 | 2025-07-01T08:45:36Z | 1019 | Social | High | Data import | 34 | 507 | resolved | |
| TCK-000003 | 2025-07-01T17:31:12Z | 1278 | Chat | Urgent | Performance | 8 | 305 | closed | |
| TCK-000004 | 2025-07-02T02:16:48Z | 1448 | Web form | Normal | Billing | 65 | open | ||
| TCK-000005 | 2025-07-02T11:02:24Z | 1936 | Low | Feature request | 431 | 3785 | closed | 4 | |
| TCK-000006 | 2025-07-02T19:48:00Z | 1471 | Social | Low | Feature request | 302 | 1808 | closed | 1 |
| TCK-000007 | 2025-07-03T04:33:36Z | 1949 | Web form | Low | Performance | 206 | 2717 | closed | 1 |
| TCK-000008 | 2025-07-03T13:19:12Z | 1968 | Chat | Normal | Billing | 85 | 771 | closed |
Ten columns, and what each one holds
| Column | Type | What it holds | Example |
|---|---|---|---|
| ticket_id | text | TCK-000001 upward, zero padded. | TCK-000001 |
| created_at | timestamp | When the ticket was opened, UTC, ascending through the file. | 2025-07-01T00:00:00Z |
| customer_id | integer | Foreign key into customers, 1001 to 2000. | 1175 |
| channel | text | Email, Chat, Phone, Web form or Social. | Chat |
| priority | text | Low, Normal, High or Urgent. | Urgent |
| category | text | What the ticket is about. | Data import |
| first_response_min | integer | Minutes to first human reply. Scales with priority the way an SLA does. | 3 |
| resolution_min | integer | Minutes to resolution. Never less than first_response_min. Blank while the ticket is open. | 412 |
| status | text | open, pending, resolved or closed. | closed |
| satisfaction | integer | CSAT 1 to 5. Blank unless the ticket is resolved or closed, and blank for the third of customers who never answer. |
What it models
A helpdesk export at the grain most support tools produce: one row per ticket, with the two clocks that management cares about and the four categorical columns that every support dashboard slices by. There is no conversation text, because the file is about durations and states rather than about content.
Priority is where the realism lives. Urgent tickets get a first response in single-digit minutes and resolve in a few hours; low priority tickets take four hours to answer and days to close. Those targets are then multiplied by a spread, so the bands overlap at the edges and the file does not look like four neat clusters. That overlap is what makes a box plot by priority interesting rather than decorative.
The blanks are the point
Two columns are deliberately incomplete, for two different reasons. resolution_min is blank when the ticket is still open or pending, because a ticket that has not been resolved has no resolution time. That is a structural null: the value does not exist, rather than being unknown.
satisfaction is blank for every unresolved ticket, and blank again for roughly a third of the resolved ones, because most people do not fill in the survey. That is a response bias null, and it is the more dangerous of the two. Average it naively and you are averaging the opinions of people who bothered to reply, which is not the same population as your customers.
Having both kinds in one file is the reason to use it for teaching missing data. A profiler reports the same thing about both columns, a percentage blank, and the correct handling of the two is completely different.
Durations with a long tail
Both clocks are integers in minutes, which is how support tools usually export them and which makes them awkward to chart. The distributions are right skewed: most tickets are quick and a few take days, so the mean sits well above the median and a linear histogram is nearly useless without bucketing or a log scale.
That is not a flaw in the data, it is the shape real duration data has, and it is the single most common reason a support dashboard gets built wrong. A file that hands you a tidy normal distribution lets you skip the problem. This one does not.
What people use it for
- Teaching the difference between a structural null and a response-bias null.
- SLA dashboards: percentage answered within target, by priority and channel.
- Duration bucketing and log-scale charts, on genuinely right-skewed data.
- Joining to customers to get ticket volume and CSAT by plan tier.
- Testing how a tool imports a column that is blank on a third of its rows.
It points at customers
customer_id is 1001-2000, the same key space as the customers dataset, so tickets per plan is a one-line join.
The pairing to try is tickets against customers on customer_id, grouped by plan. It answers a question every support organization eventually gets asked, which is whether the customers paying the most are the ones filing the most tickets, and it is a question no single-file sample dataset can even express.
Open it somewhere useful
The profiler is worth running first here, because the missing-value counts are the most interesting numbers in the file.
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.
No real customers, no real agents and no real complaints. Tickets carry only a customer_id, and the customers file it points at holds synthetic names on the reserved example.com domain. Nothing here is a support conversation anybody actually had.
Questions people ask about this file
Why is satisfaction blank on so many rows?
Two reasons, stacked. Every open or pending ticket has no score because it has not finished, and about a third of the resolved ones have no score because the customer never answered the survey. Roughly half the file therefore has a blank there. That is close to real survey response rates, and it is the trap the column exists to demonstrate: the average is an average of responders, not of customers.
Can resolution ever be faster than first response?
No. resolution_min is generated as first_response_min plus a positive duration, so the two clocks cannot invert, and a test walks the file and asserts it. This matters because an inverted duration pair is the kind of bad row that quietly poisons an average, and a sample file should not be teaching people to tolerate it.
Do the response times reflect the priority?
Yes, with overlap. Urgent targets a first response in about six minutes and a resolution in about three and a half hours; low priority targets four hours and three days. Each is then multiplied by a spread between 0.3 and 2.0, so the bands blur into each other at the edges exactly as they do in a real queue. Four cleanly separated clusters would look generated, because they would be.
Which SQL lesson is this file good for?
Multi-column grouping. Channel by priority with a count and a mean gives you a small, readable result set with real variation in it, and the blank resolution column forces the conversation about whether COUNT and AVG ignore nulls, which they do, and whether that is what you wanted, which is sometimes.
More sample data
All twenty datasets · Messy files and every other format · Build your own schema