PostgreSQL Tutorial
Data Types
Querying & Filtering Data
Managing Tables
Modifying Data
Conditionals
Control Flow
Transactions & Constraints
Working with JOINS & Schemas
Roles & Permissions
Working with Sets
Subquery & CTEs
User-defined Functions
Important In-Built Functions
PostgreSQL PL/pgSQL
Variables & Constants
Stored Procedures
Working with Triggers
Working with Views & Indexes
Errors & Exception Handling
In PostgreSQL, a Common Table Expression (CTE) provides a way to write temporary result sets that can be referenced within a SELECT
, INSERT
, UPDATE
, or DELETE
statement. CTEs are defined using the WITH
clause. They are useful for breaking down complex queries into simpler parts and can be thought of as defining temporary tables that exist just for one query.
Here's the basic syntax of a CTE:
WITH cte_name (column_name1, column_name2, ...) AS ( -- CTE Query here ) -- Main Query using the CTE SELECT ... FROM cte_name WHERE ...;
Example:
Consider a table named employees
with fields id
, name
, and salary
. If you want to find employees who earn above the average salary, you can use a CTE:
WITH AverageSalary (avg_salary) AS ( SELECT AVG(salary) FROM employees ) SELECT id, name, salary FROM employees WHERE salary > (SELECT avg_salary FROM AverageSalary);
In the example above:
AverageSalary
is created to calculate the average salary from the employees
table.CTEs can also be chained or used recursively. Recursive CTEs are especially powerful for tasks like traversing hierarchies.
Recursive CTE Example:
Consider a table hierarchy
with id
and parent_id
fields indicating a tree structure. If you wish to find the entire subtree under a particular node:
WITH RECURSIVE SubTree AS ( SELECT id, parent_id FROM hierarchy WHERE id = YOUR_STARTING_NODE_ID UNION ALL SELECT h.id, h.parent_id FROM hierarchy h JOIN SubTree st ON h.parent_id = st.id ) SELECT * FROM SubTree;
In the recursive CTE:
UNION ALL
) selects the starting node.UNION ALL
) then expands the hierarchy by joining the CTE with the hierarchy
table based on parent-child relationships.When using CTEs, especially recursive ones, be cautious. Ensure you understand the logic, as it's easy to write a recursive CTE that can run endlessly if not correctly structured.
Creating and using CTEs in PostgreSQL:
WITH your_cte AS ( SELECT column1, column2 FROM your_table WHERE condition ) SELECT * FROM your_cte;
Recursive CTEs in PostgreSQL for hierarchical data:
WITH RECURSIVE your_cte AS ( SELECT id, parent_id FROM your_table WHERE parent_id IS NULL UNION SELECT t.id, t.parent_id FROM your_table t JOIN your_cte c ON t.parent_id = c.id ) SELECT * FROM your_cte;
Common use cases for CTEs in PostgreSQL:
WITH your_cte AS ( -- Your CTE logic here ) SELECT * FROM your_cte;
Optimizing queries with CTEs in PostgreSQL:
WITH your_cte AS ( -- Your CTE logic here ) SELECT * FROM your_cte WHERE condition;
Combining CTEs with JOINs and subqueries in PostgreSQL:
WITH your_cte AS ( -- Your CTE logic here ) SELECT * FROM your_table JOIN your_cte ON your_table.id = your_cte.id;
CTEs vs. temporary tables in PostgreSQL:
-- Using CTE WITH your_cte AS ( -- Your CTE logic here ) SELECT * FROM your_cte; -- Using temporary table CREATE TEMP TABLE temp_table AS SELECT * FROM your_table; SELECT * FROM temp_table;
Managing multiple CTEs in a single query in PostgreSQL:
WITH cte1 AS ( -- CTE1 logic here ), cte2 AS ( -- CTE2 logic here ) SELECT * FROM cte1 JOIN cte2 ON cte1.id = cte2.id;