2 -- Tests for common table expressions (WITH query, ... SELECT ...)
6 WITH q1(x,y) AS (SELECT 1,2)
7 SELECT * FROM q1, q1 AS q2;
9 -- Multiple uses are evaluated only once
10 SELECT count(*) FROM (
11 WITH q1(x) AS (SELECT random() FROM generate_series(1, 5))
20 WITH RECURSIVE t(n) AS (
23 SELECT n+1 FROM t WHERE n < 100
27 WITH RECURSIVE t(n) AS (
30 SELECT n+1 FROM t WHERE n < 5
34 -- This is an infinite loop with UNION ALL, but not with UNION
35 WITH RECURSIVE t(n) AS (
41 -- This'd be an infinite loop, but outside query reads only as much as needed
42 WITH RECURSIVE t(n) AS (
46 SELECT * FROM t LIMIT 10;
48 -- UNION case should have same property
49 WITH RECURSIVE t(n) AS (
53 SELECT * FROM t LIMIT 10;
55 -- Test behavior with an unknown-type literal in the WITH
56 WITH q AS (SELECT 'foo' AS x)
57 SELECT x, x IS OF (unknown) as is_unknown FROM q;
59 WITH RECURSIVE t(n) AS (
62 SELECT n || ' bar' FROM t WHERE length(n) < 20
64 SELECT n, n IS OF (text) as is_text FROM t;
67 -- Some examples with a tree
69 -- department structure represented here is as follows:
71 -- ROOT-+->A-+->B-+->C
76 CREATE TEMP TABLE department (
77 id INTEGER PRIMARY KEY, -- department ID
78 parent_department INTEGER REFERENCES department, -- upper department ID
79 name TEXT -- department name
82 INSERT INTO department VALUES (0, NULL, 'ROOT');
83 INSERT INTO department VALUES (1, 0, 'A');
84 INSERT INTO department VALUES (2, 1, 'B');
85 INSERT INTO department VALUES (3, 2, 'C');
86 INSERT INTO department VALUES (4, 2, 'D');
87 INSERT INTO department VALUES (5, 0, 'E');
88 INSERT INTO department VALUES (6, 4, 'F');
89 INSERT INTO department VALUES (7, 5, 'G');
92 -- extract all departments under 'A'. Result should be A, B, C, D and F
93 WITH RECURSIVE subdepartment AS
96 SELECT name as root_name, * FROM department WHERE name = 'A'
101 SELECT sd.root_name, d.* FROM department AS d, subdepartment AS sd
102 WHERE d.parent_department = sd.id
104 SELECT * FROM subdepartment ORDER BY name;
106 -- extract all departments under 'A' with "level" number
107 WITH RECURSIVE subdepartment(level, id, parent_department, name) AS
109 -- non recursive term
110 SELECT 1, * FROM department WHERE name = 'A'
115 SELECT sd.level + 1, d.* FROM department AS d, subdepartment AS sd
116 WHERE d.parent_department = sd.id
118 SELECT * FROM subdepartment ORDER BY name;
120 -- extract all departments under 'A' with "level" number.
121 -- Only shows level 2 or more
122 WITH RECURSIVE subdepartment(level, id, parent_department, name) AS
124 -- non recursive term
125 SELECT 1, * FROM department WHERE name = 'A'
130 SELECT sd.level + 1, d.* FROM department AS d, subdepartment AS sd
131 WHERE d.parent_department = sd.id
133 SELECT * FROM subdepartment WHERE level >= 2 ORDER BY name;
135 -- "RECURSIVE" is ignored if the query has no self-reference
136 WITH RECURSIVE subdepartment AS
138 -- note lack of recursive UNION structure
139 SELECT * FROM department WHERE name = 'A'
141 SELECT * FROM subdepartment ORDER BY name;
144 SELECT count(*) FROM (
145 WITH RECURSIVE t(n) AS (
146 SELECT 1 UNION ALL SELECT n + 1 FROM t WHERE n < 500
148 SELECT * FROM t) AS t WHERE n < (
149 SELECT count(*) FROM (
150 WITH RECURSIVE t(n) AS (
151 SELECT 1 UNION ALL SELECT n + 1 FROM t WHERE n < 100
153 SELECT * FROM t WHERE n < 50000
154 ) AS t WHERE n < 100);
156 -- use same CTE twice at different subquery levels
158 SELECT hundred, sum(ten) FROM tenk1 GROUP BY hundred
160 SELECT count(*) FROM q1 WHERE y > (SELECT sum(y)/100 FROM q1 qsub);
163 CREATE TEMPORARY VIEW vsubdepartment AS
164 WITH RECURSIVE subdepartment AS
166 -- non recursive term
167 SELECT * FROM department WHERE name = 'A'
170 SELECT d.* FROM department AS d, subdepartment AS sd
171 WHERE d.parent_department = sd.id
173 SELECT * FROM subdepartment;
175 SELECT * FROM vsubdepartment ORDER BY name;
177 -- Check reverse listing
178 SELECT pg_get_viewdef('vsubdepartment'::regclass);
179 SELECT pg_get_viewdef('vsubdepartment'::regclass, true);
181 -- corner case in which sub-WITH gets initialized first
182 with recursive q as (
183 select * from department
185 (with x as (select * from q)
188 select * from q limit 24;
190 with recursive q as (
191 select * from department
193 (with recursive x as (
194 select * from department
196 (select * from q union all select * from x)
200 select * from q limit 32;
202 -- recursive term has sub-UNION
203 WITH RECURSIVE t(i,j) AS (
206 SELECT t2.i, t.j+1 FROM
207 (SELECT 2 AS i UNION ALL SELECT 3 AS i) AS t2
208 JOIN t ON (t2.i = t.i+1))
213 -- different tree example
215 CREATE TEMPORARY TABLE tree(
216 id INTEGER PRIMARY KEY,
217 parent_id INTEGER REFERENCES tree(id)
221 VALUES (1, NULL), (2, 1), (3,1), (4,2), (5,2), (6,2), (7,3), (8,3),
222 (9,4), (10,4), (11,7), (12,7), (13,7), (14, 9), (15,11), (16,11);
225 -- get all paths from "second level" nodes to leaf nodes
227 WITH RECURSIVE t(id, path) AS (
228 VALUES(1,ARRAY[]::integer[])
230 SELECT tree.id, t.path || tree.id
231 FROM tree JOIN t ON (tree.parent_id = t.id)
233 SELECT t1.*, t2.* FROM t AS t1 JOIN t AS t2 ON
234 (t1.path[1] = t2.path[1] AND
235 array_upper(t1.path,1) = 1 AND
236 array_upper(t2.path,1) > 1)
237 ORDER BY t1.id, t2.id;
240 WITH RECURSIVE t(id, path) AS (
241 VALUES(1,ARRAY[]::integer[])
243 SELECT tree.id, t.path || tree.id
244 FROM tree JOIN t ON (tree.parent_id = t.id)
246 SELECT t1.id, count(t2.*) FROM t AS t1 JOIN t AS t2 ON
247 (t1.path[1] = t2.path[1] AND
248 array_upper(t1.path,1) = 1 AND
249 array_upper(t2.path,1) > 1)
253 -- this variant tickled a whole-row-variable bug in 8.4devel
254 WITH RECURSIVE t(id, path) AS (
255 VALUES(1,ARRAY[]::integer[])
257 SELECT tree.id, t.path || tree.id
258 FROM tree JOIN t ON (tree.parent_id = t.id)
260 SELECT t1.id, t2.path, t2 FROM t AS t1 JOIN t AS t2 ON
264 -- test cycle detection
266 create temp table graph( f int, t int, label text );
268 insert into graph values
269 (1, 2, 'arc 1 -> 2'),
270 (1, 3, 'arc 1 -> 3'),
271 (2, 3, 'arc 2 -> 3'),
272 (1, 4, 'arc 1 -> 4'),
273 (4, 5, 'arc 4 -> 5'),
274 (5, 1, 'arc 5 -> 1');
276 with recursive search_graph(f, t, label, path, cycle) as (
277 select *, array[row(g.f, g.t)], false from graph g
279 select g.*, path || row(g.f, g.t), row(g.f, g.t) = any(path)
280 from graph g, search_graph sg
281 where g.f = sg.t and not cycle
283 select * from search_graph;
285 -- ordering by the path column has same effect as SEARCH DEPTH FIRST
286 with recursive search_graph(f, t, label, path, cycle) as (
287 select *, array[row(g.f, g.t)], false from graph g
289 select g.*, path || row(g.f, g.t), row(g.f, g.t) = any(path)
290 from graph g, search_graph sg
291 where g.f = sg.t and not cycle
293 select * from search_graph order by path;
296 -- test multiple WITH queries
299 y (id) AS (VALUES (1)),
300 x (id) AS (SELECT * FROM y UNION ALL SELECT id+1 FROM x WHERE id < 5)
303 -- forward reference OK
305 x(id) AS (SELECT * FROM y UNION ALL SELECT id+1 FROM x WHERE id < 5),
306 y(id) AS (values (1))
311 (VALUES (1) UNION ALL SELECT id+1 FROM x WHERE id < 5),
313 (VALUES (1) UNION ALL SELECT id+1 FROM y WHERE id < 10)
314 SELECT y.*, x.* FROM y LEFT JOIN x USING (id);
318 (VALUES (1) UNION ALL SELECT id+1 FROM x WHERE id < 5),
320 (VALUES (1) UNION ALL SELECT id+1 FROM x WHERE id < 10)
321 SELECT y.*, x.* FROM y LEFT JOIN x USING (id);
325 (SELECT 1 UNION ALL SELECT id+1 FROM x WHERE id < 3 ),
327 (SELECT * FROM x UNION ALL SELECT * FROM x),
329 (SELECT * FROM x UNION ALL SELECT id+1 FROM z WHERE id < 10)
334 (SELECT 1 UNION ALL SELECT id+1 FROM x WHERE id < 3 ),
336 (SELECT * FROM x UNION ALL SELECT * FROM x),
338 (SELECT * FROM y UNION ALL SELECT id+1 FROM z WHERE id < 10)
346 WITH RECURSIVE x(n) AS (SELECT 1 INTERSECT SELECT n+1 FROM x)
349 WITH RECURSIVE x(n) AS (SELECT 1 INTERSECT ALL SELECT n+1 FROM x)
353 WITH RECURSIVE x(n) AS (SELECT 1 EXCEPT SELECT n+1 FROM x)
356 WITH RECURSIVE x(n) AS (SELECT 1 EXCEPT ALL SELECT n+1 FROM x)
359 -- no non-recursive term
360 WITH RECURSIVE x(n) AS (SELECT n FROM x)
363 -- recursive term in the left hand side (strictly speaking, should allow this)
364 WITH RECURSIVE x(n) AS (SELECT n FROM x UNION ALL SELECT 1)
367 CREATE TEMPORARY TABLE y (a INTEGER);
368 INSERT INTO y SELECT generate_series(1, 10);
372 WITH RECURSIVE x(n) AS (SELECT a FROM y WHERE a = 1
374 SELECT x.n+1 FROM y LEFT JOIN x ON x.n = y.a WHERE n < 10)
378 WITH RECURSIVE x(n) AS (SELECT a FROM y WHERE a = 1
380 SELECT x.n+1 FROM x RIGHT JOIN y ON x.n = y.a WHERE n < 10)
384 WITH RECURSIVE x(n) AS (SELECT a FROM y WHERE a = 1
386 SELECT x.n+1 FROM x FULL JOIN y ON x.n = y.a WHERE n < 10)
390 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x
391 WHERE n IN (SELECT * FROM x))
394 -- aggregate functions
395 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT count(*) FROM x)
398 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT sum(n) FROM x)
402 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x ORDER BY 1)
406 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x LIMIT 10 OFFSET 1)
410 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x FOR UPDATE)
413 -- target list has a recursive query name
414 WITH RECURSIVE x(id) AS (values (1)
416 SELECT (SELECT * FROM x) FROM x WHERE id < 5
419 -- mutual recursive query (not implemented)
421 x (id) AS (SELECT 1 UNION ALL SELECT id+1 FROM y WHERE id < 5),
422 y (id) AS (SELECT 1 UNION ALL SELECT id+1 FROM x WHERE id < 5)
425 -- non-linear recursion is not allowed
426 WITH RECURSIVE foo(i) AS
429 (SELECT i+1 FROM foo WHERE i < 10
431 SELECT i+1 FROM foo WHERE i < 5)
434 WITH RECURSIVE foo(i) AS
438 (SELECT i+1 FROM foo WHERE i < 10
440 SELECT i+1 FROM foo WHERE i < 5) AS t
443 WITH RECURSIVE foo(i) AS
446 (SELECT i+1 FROM foo WHERE i < 10
448 SELECT i+1 FROM foo WHERE i < 5)
451 WITH RECURSIVE foo(i) AS
454 (SELECT i+1 FROM foo WHERE i < 10
456 SELECT i+1 FROM foo WHERE i < 5)
459 -- Wrong type induced from non-recursive term
460 WITH RECURSIVE foo(i) AS
461 (SELECT i FROM (VALUES(1),(2)) t(i)
463 SELECT (i+1)::numeric(10,0) FROM foo WHERE i < 10)
466 -- rejects different typmod, too (should we allow this?)
467 WITH RECURSIVE foo(i) AS
468 (SELECT i::numeric(3,0) FROM (VALUES(1),(2)) t(i)
470 SELECT (i+1)::numeric(10,0) FROM foo WHERE i < 10)
474 -- test for bug #4902
476 with cte(foo) as ( values(42) ) values((select foo from cte));
477 with cte(foo) as ( select 42 ) select * from ((select foo from cte)) q;
479 -- test CTE referencing an outer-level variable (to see that changed-parameter
480 -- signaling still works properly after fixing this bug)
481 select ( with cte(foo) as ( values(f1) )
482 select (select foo from cte) )
485 select ( with cte(foo) as ( values(f1) )
486 values((select foo from cte)) )
490 -- test for nested-recursive-WITH bug
492 WITH RECURSIVE t(j) AS (
493 WITH RECURSIVE s(i) AS (
496 SELECT i+1 FROM s WHERE i < 10
500 SELECT j+1 FROM t WHERE j < 10