Skip to main content

VillageSQL is a drop-in replacement for MySQL with extensions.

All examples on this page work on VillageSQL. Install Now →
A common table expression gives a query a name, at the top, before the query that uses it. The result is the same as a derived table, and it reads in the order you think: define the pieces, then use them. Open the client with mysql -u root -p sakila before you start.

How a CTE works

Replace CTE_NAME with a name for the intermediate result, COLUMN_LIST with the columns you want, and TABLE_NAME with the table the inner query reads. The main query then reads CTE_NAME as if it were a table. A CTE lasts for 1 statement. It is not stored, and the next query knows nothing about it.

Examples

1) One named step

The same rows the derived table lesson returns, with the counting lifted out of FROM and given a name.

2) Several steps, each built on the last

Separate CTEs with a comma, and a later one may read an earlier one. That is what a derived table cannot do without repeating itself.
busiest reads counts, and the main query reads both. Written as derived tables, the counting query would appear twice.

What a CTE gives you that a derived table does not

The rows are the same either way. 2 things differ:
  • A CTE carries a name, so a 3-stage query reads top to bottom. counts and busiest tell the next reader what each piece is for.
  • A CTE can be named more than once in the same statement. A derived table has to be written out again.
Whether the optimizer treats the 2 forms differently is a separate question, and When a MySQL CTE beats a derived table measures it.

Summary

  • Use WITH name AS (...) to name a query before the query that reads it.
  • Separate several CTEs with commas, and let a later one read an earlier one.
  • Expect a CTE to last for 1 statement only.
  • Prefer a CTE when a query has several stages or repeats a subquery.

See also