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

PostgreSQL - CTE

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:

  1. A CTE named AverageSalary is created to calculate the average salary from the employees table.
  2. The main query then fetches all employees whose salary is above this average.

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:

  1. The non-recursive term (before the UNION ALL) selects the starting node.
  2. The recursive term (after the UNION ALL) then expands the hierarchy by joining the CTE with the hierarchy table based on parent-child relationships.
  3. This continues until no more children are found, and the entire subtree is fetched.

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.

  1. Creating and using CTEs in PostgreSQL:

    • Description: Defines a temporary result set that can be referenced within a SELECT, INSERT, UPDATE, or DELETE statement.
    • Code:
      WITH your_cte AS (
          SELECT column1, column2
          FROM your_table
          WHERE condition
      )
      SELECT * FROM your_cte;
      
  2. Recursive CTEs in PostgreSQL for hierarchical data:

    • Description: Enables querying hierarchical data using recursive queries.
    • Code:
      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;
      
  3. Common use cases for CTEs in PostgreSQL:

    • Description: Solves problems like data transformation, aggregation, and simplifying complex queries.
    • Code:
      WITH your_cte AS (
          -- Your CTE logic here
      )
      SELECT * FROM your_cte;
      
  4. Optimizing queries with CTEs in PostgreSQL:

    • Description: Improves query readability and performance by breaking it into modular parts.
    • Code:
      WITH your_cte AS (
          -- Your CTE logic here
      )
      SELECT * FROM your_cte
      WHERE condition;
      
  5. Combining CTEs with JOINs and subqueries in PostgreSQL:

    • Description: Integrates CTEs with other SQL constructs for more complex queries.
    • Code:
      WITH your_cte AS (
          -- Your CTE logic here
      )
      SELECT *
      FROM your_table
      JOIN your_cte ON your_table.id = your_cte.id;
      
  6. CTEs vs. temporary tables in PostgreSQL:

    • Description: Compares the use of CTEs with temporary tables for storing intermediate results.
    • Code:
      -- 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;
      
  7. Managing multiple CTEs in a single query in PostgreSQL:

    • Description: Utilizes multiple CTEs within a single query.
    • Code:
      WITH cte1 AS (
          -- CTE1 logic here
      ),
      cte2 AS (
          -- CTE2 logic here
      )
      SELECT *
      FROM cte1
      JOIN cte2 ON cte1.id = cte2.id;