WITH statement (Common Table Expressions)
A common table expression (CTE) is a named temporary result set that exists within the scope of a single statement and that can be referred to later within that statement, possibly multiple times. The following discussion describes how to write statements that use CTEs.
Syntax
|--WITH -------------------------------------------------------------------------> (1)
.-,-----------------------------------------------------------------------+
V |
(1)----- cte_name ---+---------------------+--AS (Subset of SELECT statement)--+-> (2)
| .-,--------. |
| V | |
'-(----column---+--)-'
(2)----- SELECT/UPDATE/INSERT/DELETE statement
Element | Description | Restrictions | Syntax |
---|---|---|---|
column | Name that you declare here for a column in CTE. Default is a column name from Projection list of SELECT | Identifier | |
cte_name | Name that you declare here for the table expression, and it can be used as a virtual table in the following SELECT/UPDATE/INSERT/DELETE statement | Must be unique among view, table, sequence, and synonym names in the database. | Identifier |
Usage
WITH statement can be run directly like SELECT/UPDATE/INSERT/DELETE statements, and it can be
used with
- CREATE VIEW
- CREATE TRIGGER
- CREATE PROCEDURE/FUNCTION
Recursive CTE
A recursive CTE starts with either one non-recursive sub-query or several non-recursive sub-queries joined by UNION or UNION ALL and ends with exactly one recursive sub-query joined by UNION ALL. A recursive sub-query references the CTE being defined.
WITH recursive_cte AS (
<initial subquery>
UNION ALL
<recursive subquery>
) SELECT …
Example 1: Recursive query computing the factorial of numbers from 0 to 9
WITH temp (n, fact) AS (
SELECT 0, 1 -- Initial Subquery
UNION ALL
SELECT n+1, (n+1)*fact FROM temp -- Recursive Subquery
WHERE n < 9)
SELECT * FROM temp;
Other example of computing Fibonacci Numbers
WITH fib(p, n) as (
select 0, 1 -- initial subquery
UNION ALL -- ‘UNION ALL’
select n, (p+n) from fib -- recursive subquery
where n < 100 -- terminate condition
)
select p as fn from fib;
fn
0
1
1
2
…
34
55
89
Example 2: Recursive CTE optional Cycle clause
CYCLE <column list> SET <cycle pseudo column>
TO <value1> DEFAULT <value2>
create table cycle (id int, pid int);
insert into cycle values (1,2);
insert into cycle values (2,1);
WITH cte AS (
select id, pid from cycle where id = 1 UNION ALL
select t.id, t.pid
from cycle t, cte where t.pid = cte.id)
cycle id set iscycle to "yes" default "no"
SELECT id, pid, iscycle from cte ;
id pid iscycle
1 2 no
2 1 yes
Example 3: Recursive CTE Loops
with cte(n) as
(
select 1
UNION ALL
select n+1 from cte
)
select first 2 n from cte; -- 2 rows return
without the ‘FIRST 2’ the query will loop till integer limit error.