Technical skill practice
SQL CTE: Build a Report in Readable Stages
A common table expression names a query result for use within one statement. Use it to make a calculation readable when one stage produces the input for another. Naming a CTE does not itself promise that a database stores it or runs it faster.
The practice task
A training coordinator wants departments with more than one completed course registration. Count completed registrations first, then filter that result. The sample keeps cancelled registrations in the source so a missing status filter produces an observable mistake.
The data below is fictional. Run the example in a new SQLite database. It was checked with SQLite 3.51.0; other databases may use different syntax, functions or type rules.
Complete worked query
Create the small fixture and run the query together. The IDs, boundary values and missing entries make the result small enough to check by hand.
CREATE TABLE registrations(dept TEXT, status TEXT);
INSERT INTO registrations VALUES ('Support','completed'),('Support','completed'),('Support','cancelled'),('Design','completed'),('Design','cancelled');
WITH completed AS (
SELECT dept, COUNT(*) AS total
FROM registrations
WHERE status = 'completed'
GROUP BY dept
), qualifying AS (
SELECT dept, total FROM completed WHERE total > 1
)
SELECT dept, total FROM qualifying ORDER BY dept;Checked result
This is the result of the exact example above. NULL marks a missing database value rather than the text string "NULL".
Result rows
dept | total
Support | 2
Read the result
The first CTE reduces five registrations to two department totals: Support has two completions and Design has one. The second keeps only the department above the threshold. Reading those stages separately makes the population and the threshold easy to inspect.
Filtering status after aggregation would lose the distinction between completed and cancelled registrations unless status were also retained as a grouping key. Put a row condition where the relevant row information still exists. The result is one Support row, not three registrations.
For a small query, a derived table or HAVING condition may be simpler. Choose a CTE when the names explain a real sequence of work. Compare an execution plan before claiming a performance benefit; a cleaner explanation and a faster query are different outcomes.
Mistakes to check
Use these checks when adapting the example to a different dataset.
- The CTE name lasts for this statement, not the next statement.
- Do not give two stages vague names such as data1 and data2.
- Count the intended population before applying a group threshold.
Questions, answered
Can I run this example as written?
Yes, in a new SQLite database using the schema and values shown. The result above was checked with SQLite 3.51.0. Keep it separate from an existing database.
What changes if the coordinator wants departments with at least one cancelled registration as well?
Create a separate cancelled-registration total or a conditional aggregate and join the department results. Keep the completed threshold and cancellation condition separate so neither changes the meaning of the other.
Sources and examples
ResumizeAI team. Examples are fictional teaching material, not customer results. Replace sample details with your own facts.
Your experience. A complete resume.
Build in Resumize with ATS-friendly templates, guided editing and a live preview. Start free, then upgrade when you need more.
Free account required. Free-plan PDF exports include a watermark.