6.1.14. Common Table Expressions (“WITH …​ AS …​ SELECT”)

Available in

DSQL, PSQL

A common table expression or CTE can be described as a virtual table or view, defined in a preamble to a main query, and going out of scope after the main query’s execution. The main query can reference any CTEs defined in the preamble as if they were regular tables or views. CTEs can be recursive, i.e. self-referencing, but they cannot be nested.

Syntax

  1. <cte-construct> ::=
  2. <cte-defs>
  3. <main-query>
  4. <cte-defs> ::= WITH [RECURSIVE] <cte> [, <cte> ...]
  5. <cte> ::= name [(<column-list>)] AS (<cte-stmt>)
  6. <column-list> ::= column-alias [, column-alias ...]
Table 71. Arguments for Common Table Expressions
ArgumentDescription

cte-stmt

Any SELECT statement, including UNION

main-query

The main SELECT statement, which can refer to the CTEs defined in the preamble

name

Alias for a table expression

column-alias

Alias for a column in a table expression

Example

  1. with dept_year_budget as (
  2. select fiscal_year,
  3. dept_no,
  4. sum(projected_budget) as budget
  5. from proj_dept_budget
  6. group by fiscal_year, dept_no
  7. )
  8. select d.dept_no,
  9. d.department,
  10. dyb_2008.budget as budget_08,
  11. dyb_2009.budget as budget_09
  12. from department d
  13. left join dept_year_budget dyb_2008
  14. on d.dept_no = dyb_2008.dept_no
  15. and dyb_2008.fiscal_year = 2008
  16. left join dept_year_budget dyb_2009
  17. on d.dept_no = dyb_2009.dept_no
  18. and dyb_2009.fiscal_year = 2009
  19. where exists (
  20. select * from proj_dept_budget b
  21. where d.dept_no = b.dept_no
  22. );

CTE Notes

  • A CTE definition can contain any legal SELECT statement, as long as it doesn’t have a “WITH…​” preamble of its own (no nesting).

  • CTEs defined for the same main query can reference each other, but care should be taken to avoid loops.

  • CTEs can be referenced from anywhere in the main query.

  • Each CTE can be referenced multiple times in the main query, using different aliases if necessary.

  • When enclosed in parentheses, CTE constructs can be used as subqueries in SELECT statements, but also in UPDATEs, MERGEs etc.

  • In PSQL, CTEs are also supported in FOR loop headers:

    1. for
    2. with my_rivers as (select * from rivers where owner = 'me')
    3. select name, length from my_rivers into :rname, :rlen
    4. do
    5. begin
    6. ..
    7. end

If a CTE is declared, it must be used later: otherwise, you will get an error like this: ‘CTE “AAA” is not used in query’.

Recursive CTEs

A recursive (self-referencing) CTE is a UNION which must have at least one non-recursive member, called the anchor. The non-recursive member(s) must be placed before the recursive member(s). Recursive members are linked to each other and to their non-recursive neighbour by UNION ALL operators. The unions between non-recursive members may be of any type.

Recursive CTEs require the RECURSIVE keyword to be present right after WITH. Each recursive union member may reference itself only once, and it must do so in a FROM clause.

A great benefit of recursive CTEs is that they use far less memory and CPU cycles than an equivalent recursive stored procedure.

Execution Pattern

The execution pattern of a recursive CTE is as follows:

  • The engine begins execution from a non-recursive member.

  • For each row evaluated, it starts executing each recursive member one by one, using the current values from the outer row as parameters.

  • If the currently executing instance of a recursive member produces no rows, execution loops back one level and gets the next row from the outer result set.

Example of recursive CTEs

  1. WITH RECURSIVE DEPT_YEAR_BUDGET AS (
  2. SELECT
  3. FISCAL_YEAR,
  4. DEPT_NO,
  5. SUM(PROJECTED_BUDGET) BUDGET
  6. FROM PROJ_DEPT_BUDGET
  7. GROUP BY FISCAL_YEAR, DEPT_NO
  8. ),
  9. DEPT_TREE AS (
  10. SELECT
  11. DEPT_NO,
  12. HEAD_DEPT,
  13. DEPARTMENT,
  14. CAST('' AS VARCHAR(255)) AS INDENT
  15. FROM DEPARTMENT
  16. WHERE HEAD_DEPT IS NULL
  17. UNION ALL
  18. SELECT
  19. D.DEPT_NO,
  20. D.HEAD_DEPT,
  21. D.DEPARTMENT,
  22. H.INDENT || ' '
  23. FROM DEPARTMENT D
  24. JOIN DEPT_TREE H ON H.HEAD_DEPT = D.DEPT_NO
  25. )
  26. SELECT
  27. D.DEPT_NO,
  28. D.INDENT || D.DEPARTMENT DEPARTMENT,
  29. DYB_2008.BUDGET AS BUDGET_08,
  30. DYB_2009.BUDGET AS BUDGET_09
  31. FROM DEPT_TREE D
  32. LEFT JOIN DEPT_YEAR_BUDGET DYB_2008 ON
  33. (D.DEPT_NO = DYB_2008.DEPT_NO) AND
  34. (DYB_2008.FISCAL_YEAR = 2008)
  35. LEFT JOIN DEPT_YEAR_BUDGET DYB_2009 ON
  36. (D.DEPT_NO = DYB_2009.DEPT_NO) AND
  37. (DYB_2009.FISCAL_YEAR = 2009);

The next example returns the pedigree of a horse. The main difference is that recursion occurs simultaneously in two branches of the pedigree.

  1. WITH RECURSIVE PEDIGREE (
  2. CODE_HORSE,
  3. CODE_FATHER,
  4. CODE_MOTHER,
  5. NAME,
  6. MARK,
  7. DEPTH)
  8. AS (SELECT
  9. HORSE.CODE_HORSE,
  10. HORSE.CODE_FATHER,
  11. HORSE.CODE_MOTHER,
  12. HORSE.NAME,
  13. CAST('' AS VARCHAR(80)),
  14. 0
  15. FROM
  16. HORSE
  17. WHERE
  18. HORSE.CODE_HORSE = :CODE_HORSE
  19. UNION ALL
  20. SELECT
  21. HORSE.CODE_HORSE,
  22. HORSE.CODE_FATHER,
  23. HORSE.CODE_MOTHER,
  24. HORSE.NAME,
  25. 'F' || PEDIGREE.MARK,
  26. PEDIGREE.DEPTH + 1
  27. FROM
  28. HORSE
  29. JOIN PEDIGREE
  30. ON HORSE.CODE_HORSE = PEDIGREE.CODE_FATHER
  31. WHERE
  32. PEDIGREE.DEPTH < :MAX_DEPTH
  33. UNION ALL
  34. SELECT
  35. HORSE.CODE_HORSE,
  36. HORSE.CODE_FATHER,
  37. HORSE.CODE_MOTHER,
  38. HORSE.NAME,
  39. 'M' || PEDIGREE.MARK,
  40. PEDIGREE.DEPTH + 1
  41. FROM
  42. HORSE
  43. JOIN PEDIGREE
  44. ON HORSE.CODE_HORSE = PEDIGREE.CODE_MOTHER
  45. WHERE
  46. PEDIGREE.DEPTH < :MAX_DEPTH
  47. )
  48. SELECT
  49. CODE_HORSE,
  50. NAME,
  51. MARK,
  52. DEPTH
  53. FROM
  54. PEDIGREE

Notes on recursive CTEs

  • Aggregates (DISTINCT, GROUP BY, HAVING) and aggregate functions (SUM, COUNT, MAX etc) are not allowed in recursive union members.

  • A recursive reference cannot participate in an outer join.

  • The maximum recursion depth is 1024.