user: What is the purpose of common table expressions in SQL and when should you use them?

assistant: A Common Table Expression (CTE) is a temporary result set derived from a SELECT statement, and can be used in a SELECT, INSERT, UPDATE, or DELETE statement. CTEs are used to simplify complex queries by breaking them down into smaller, more manageable pieces.

The purpose of CTEs is to make queries easier to read, write and maintain. CTEs can be thought of as named subqueries or temporary views that are only visible within the scope of a single SELECT, INSERT, UPDATE, or DELETE statement. They are not stored as objects in the database and do not impact database performance.

CTEs are particularly useful when dealing with complex queries that involve multiple levels of data aggregation or calculations, or when the same subquery is used in multiple places in a larger query. Using a CTE allows you to write the subquery once and reuse it throughout the query, making the overall structure of the query simpler and easier to understand.

In terms of when to use CTEs, they are a good choice when you want to:

Break down a complex query into smaller, more manageable pieces.
Improve query readability and maintainability by giving meaningful names to intermediate results.
Reuse intermediate results within the same query.
Simplify complex calculations or aggregations by breaking them down into multiple steps.
In general, if you have a query that is becoming difficult to understand or maintain due to its complexity, a CTE may be a good solution to simplify the query and make it easier to work with.

user: What are some basic examples?

assistant: Let’s say you have a table called schools with the columns ```school_id```, ```school_name```, ```district_id```, and the number of students.
You need to write a query to display a list of schools alongside their district ID and the average number of students per school in that district.

Your logic might be as follows:

    Create a table with the list of districts and the corresponding average number of students per school.
    Join this table with the list of schools and display the required information.
    Drop the table with the average number of students per school for each district.

If you use a CTE (Common Table Expression), you don’t need to create and drop a table. You can simply reference the temporary result set created by the "WITH" query, like you see below:

```
WITH avg_students AS (
SELECT district_id, AVG(students) as average_students
FROM schools
GROUP BY district_id)
SELECT s.school_name, s.district_id, avg.average_students
FROM schools s
JOIN avg_students avg
ON s.district_id = avg.district_id;
```

So, here you start by defining the temporary result set ```avg_students``` in the "WITH" query. In the brackets, there is a "SELECT" statement that defines this result set; it contains a list of districts and the corresponding average number of students per school. After the closing parenthesis, you start the main "SELECT" statement. Notice that you reference the temporary result set just like an ordinary table, using its assigned name (```avg_students```). The output will include the school name, the ID of its district, and the average number of students in this district. 


| school_name | district_id | average_students |
| --- | --- | --- |
| Happy Kid | 2 | 238 |
| Smart | 2 | 238 |
| Sun | 5 | 176 |
| Montessori | 5 | 176 |


In the sense that it can’t be used in any other SQL queries, the temporary result set is “dropped”. Of course, you can define it again if you need to.