CTEs can be categorized into two types: non-recursive and recursive. Non-recursive CTEs are used for simple queries, while recursive CTEs are useful for hierarchical data structures. This article will cover both types, focusing on their syntax, use cases, and best practices.

Non-Recursive CTEs

A non-recursive CTE is defined using the WITH clause and can be thought of as a temporary result set that you can reference within a SELECT, INSERT, UPDATE, or DELETE statement.

Syntax

WITH cte_name AS (
    SELECT column1, column2
    FROM table_name
    WHERE condition
)
SELECT *
FROM cte_name;

Example

Let’s say we have a table called employees with the following structure:

employee_idfirst_namelast_namedepartmentsalary
1JohnDoeHR60000
2JaneSmithIT80000
3AliceJohnsonHR65000
4BobBrownIT70000

We want to find the average salary of employees in each department. Instead of writing a complex query, we can use a CTE:

WITH department_salaries AS (
    SELECT department, AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department
)
SELECT *
FROM department_salaries;

Output

departmentavg_salary
HR62500
IT75000

Recursive CTEs

Recursive CTEs are particularly useful for querying hierarchical data, such as organizational structures or bill of materials. They consist of two parts: the anchor member and the recursive member.

Syntax

WITH RECURSIVE cte_name AS (
    -- Anchor member
    SELECT column1, column2
    FROM table_name
    WHERE condition
    UNION ALL
    -- Recursive member
    SELECT column1, column2
    FROM table_name
    JOIN cte_name ON table_name.parent_id = cte_name.id
)
SELECT *
FROM cte_name;

Example

Consider a simple organizational structure where each employee has a manager_id that refers to their manager. The employees table might look like this:

employee_idfirst_namelast_namemanager_id
1JohnDoeNULL
2JaneSmith1
3AliceJohnson1
4BobBrown2

To retrieve the hierarchy of employees under John Doe, we can use a recursive CTE:

WITH RECURSIVE employee_hierarchy AS (
    -- Anchor member
    SELECT employee_id, first_name, last_name, manager_id
    FROM employees
    WHERE employee_id = 1
    UNION ALL
    -- Recursive member
    SELECT e.employee_id, e.first_name, e.last_name, e.manager_id
    FROM employees e
    JOIN employee_hierarchy eh ON e.manager_id = eh.employee_id
)
SELECT *
FROM employee_hierarchy;

Output

employee_idfirst_namelast_namemanager_id
1JohnDoeNULL
2JaneSmith1
3AliceJohnson1
4BobBrown2

Best Practices for Using CTEs

  1. Readability: Use CTEs to improve the readability of your SQL queries. Break complex logic into smaller, manageable pieces.
  2. Performance: While CTEs can simplify queries, be aware that they may not always be optimized by the database engine. Test performance and consider alternatives if necessary.
  3. Scope: Remember that CTEs are only valid within the execution of the immediate query. They cannot be reused in subsequent queries.
  4. Limit Recursion: When using recursive CTEs, always ensure there is a termination condition to prevent infinite loops.

Conclusion

Common Table Expressions are an invaluable tool for SQL developers. They enhance query readability and maintainability, especially in complex scenarios involving hierarchical data. By leveraging both non-recursive and recursive CTEs, you can write cleaner, more efficient SQL code.

Learn more with useful resources: