--- title: 'PostgreSQL CTE' page_title: 'PostgreSQL Common Table Expression (CTE)' page_description: 'This tutorial shows you how to use the PostgreSQL common table expression (CTE) to simplify complex queries.' prev_url: 'https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-cte/' ogImage: '' updatedOn: '2024-01-22T06:27:22+00:00' enableTableOfContents: true previousLink: title: 'PostgreSQL EXISTS Operator' slug: 'postgresql-tutorial/postgresql-exists' nextLink: title: 'PostgreSQL Recursive Query' slug: 'postgresql-tutorial/postgresql-recursive-query' --- **Summary**: in this tutorial, you will learn how to use the PostgreSQL common table expression (CTE) to simplify complex queries. ## Introduction to PostgreSQL common table expression (CTE) A common table expression (CTE) allows you to create a temporary result set within a [query](postgresql-select). A CTE helps you enhance the readability of a complex query by breaking it down into smaller and more reusable parts Here’s the basic syntax for creating a common table expression: ```sql WITH cte_name (column1, column2, ...) AS ( -- CTE query SELECT ... ) -- Main query using the CTE SELECT ... FROM cte_name; ``` In this syntax: - **WITH clause**: Introduce the common table expression (CTE). It is followed by the name of the CTE and a list of column names in parentheses. The column list is optional and is only necessary if you want to explicitly define the columns for the CTE. - **CTE name**: Specify the name of the CTE. The CTE name exists within the scope of the query. Ensure that the CTE name is unique within the query. - **Column List (optional)**: Specify the list of column names within the parentheses after the CTE name. If not specified, the columns implicitly inherit the column names from `SELECT` statement inside the CTE. - **AS keyword**: The AS keyword indicates the beginning of the CTE definition. - **CTE query**: This is a query that defines the CTE, which may include [JOINs](postgresql-joins), [WHERE](postgresql-where), [GROUP BY](postgresql-group-by) clauses, and other valid SQL constructs. - **Main query**: After defining the CTE, you can reference it in the main query by its name. In the main query, you can use the CTE as if it were a regular table, simplifying the structure of complex queries. ## PostgreSQL CTE examples Let’s explore some examples of using common table expressions (CTE). ### 1\) Basic PostgreSQL common table expression example The following example uses a common table expression (CTE) to select the `title` and `length` of films in the `'Action'` category and returns all the columns of the CTE: ```sql WITH action_films AS ( SELECT f.title, f.length FROM film f INNER JOIN film_category fc USING (film_id) INNER JOIN category c USING(category_id) WHERE c.name = 'Action' ) SELECT * FROM action_films; ``` Output: ```text title | length -------------------------+-------- Amadeus Holy | 113 American Circus | 129 Antitrust Tomatoes | 168 Ark Ridgemont | 68 ... ``` In this example: - First, the CTE query combines data from three tables `film`, `film_category`, and `category` using the `INNER JOIN` clauses. - Then, the main query retrieves data from the `action_films` CTE using a simple `SELECT` statement. ### 2\) Join a CTE with a table example We’ll use the `rental` and `staff` tables from the [sample database](../postgresql-getting-started/postgresql-sample-database) in this example: The following example join a CTE with a table to find the staff and rental count for each: ``` WITH cte_rental AS ( SELECT staff_id, COUNT(rental_id) rental_count FROM rental GROUP BY staff_id ) SELECT s.staff_id, first_name, last_name, rental_count FROM staff s INNER JOIN cte_rental USING (staff_id); ``` In this example: - First, the CTE returns a result set that includes the staff id and the rental counts. - Then, the main query joins the `staff` table with the CTE using the `staff_id` column. Output: ```text staff_id | first_name | last_name | rental_count ----------+------------+-----------+-------------- 1 | Mike | Hillyer | 8040 2 | Jon | Stephens | 8004 (2 rows) ``` ### 3\) Multiple CTEs example The following example uses multiple CTEs to calculate various statistics related to films and customers: ``` WITH film_stats AS ( -- CTE 1: Calculate film statistics SELECT AVG(rental_rate) AS avg_rental_rate, MAX(length) AS max_length, MIN(length) AS min_length FROM film ), customer_stats AS ( -- CTE 2: Calculate customer statistics SELECT COUNT(DISTINCT customer_id) AS total_customers, SUM(amount) AS total_payments FROM payment ) -- Main query using the CTEs SELECT ROUND((SELECT avg_rental_rate FROM film_stats), 2) AS avg_film_rental_rate, (SELECT max_length FROM film_stats) AS max_film_length, (SELECT min_length FROM film_stats) AS min_film_length, (SELECT total_customers FROM customer_stats) AS total_customers, (SELECT total_payments FROM customer_stats) AS total_payments; ``` Output: ``` avg_film_rental_rate | max_film_length | min_film_length | total_customers | total_payments ----------------------+-----------------+-----------------+-----------------+---------------- 2.98 | 185 | 46 | 599 | 61312.04 (1 row) ``` In this example, we create two CTEs: - **`film_stats`:** Calculates statistics related to films including the average rental rate, maximum length, and minimum length. - **`customer_stats`:** Calculates statistics related to customers including the total number of distinct customers and the overall payments made. The main query retrieves specific values from each CTE to create a summary report. ## PostgreSQL CTE advantages The following are some advantages of using common table expressions or CTEs: - Improve the readability of complex queries. You use CTEs to organize complex queries in a more organized and readable manner. - Ability to create [recursive queries](postgresql-recursive-query), which are queries that reference themselves. The recursive queries come in handy when you want to query hierarchical data such as organization charts. - Use in conjunction with [window functions](../postgresql-window-function). You can use CTEs in conjunction with window functions to create an initial result set and use another select statement to further process this result set. ## Summary - Use a common table expression (CTE) to create a temporary result set within a query. - Leverage CTEs to simplify complex queries and make them more readable.