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'd be an infinite loop, but outside query reads only as much as needed
35 WITH RECURSIVE t(n) AS (
39 SELECT * FROM t LIMIT 10;
42 -- Some examples with a tree
44 -- department structure represented here is as follows:
46 -- ROOT-+->A-+->B-+->C
51 CREATE TEMP TABLE department (
52 id INTEGER PRIMARY KEY, -- department ID
53 parent_department INTEGER REFERENCES department, -- upper department ID
54 name TEXT -- department name
57 INSERT INTO department VALUES (0, NULL, 'ROOT');
58 INSERT INTO department VALUES (1, 0, 'A');
59 INSERT INTO department VALUES (2, 1, 'B');
60 INSERT INTO department VALUES (3, 2, 'C');
61 INSERT INTO department VALUES (4, 2, 'D');
62 INSERT INTO department VALUES (5, 0, 'E');
63 INSERT INTO department VALUES (6, 4, 'F');
64 INSERT INTO department VALUES (7, 5, 'G');
67 -- extract all departments under 'A'. Result should be A, B, C, D and F
68 WITH RECURSIVE subdepartment AS
71 SELECT * FROM department WHERE name = 'A'
76 SELECT d.* FROM department AS d, subdepartment AS sd
77 WHERE d.parent_department = sd.id
79 SELECT * FROM subdepartment ORDER BY name;
81 -- extract all departments under 'A' with "level" number
82 WITH RECURSIVE subdepartment(level, id, parent_department, name) AS
85 SELECT 1, * FROM department WHERE name = 'A'
90 SELECT sd.level + 1, d.* FROM department AS d, subdepartment AS sd
91 WHERE d.parent_department = sd.id
93 SELECT * FROM subdepartment ORDER BY name;
95 -- extract all departments under 'A' with "level" number.
96 -- Only shows level 2 or more
97 WITH RECURSIVE subdepartment(level, id, parent_department, name) AS
100 SELECT 1, * FROM department WHERE name = 'A'
105 SELECT sd.level + 1, d.* FROM department AS d, subdepartment AS sd
106 WHERE d.parent_department = sd.id
108 SELECT * FROM subdepartment WHERE level >= 2 ORDER BY name;
110 -- "RECURSIVE" is ignored if the query has no self-reference
111 WITH RECURSIVE subdepartment AS
113 -- note lack of recursive UNION structure
114 SELECT * FROM department WHERE name = 'A'
116 SELECT * FROM subdepartment ORDER BY name;
119 SELECT count(*) FROM (
120 WITH RECURSIVE t(n) AS (
121 SELECT 1 UNION ALL SELECT n + 1 FROM t WHERE n < 500
123 SELECT * FROM t) AS t WHERE n < (
124 SELECT count(*) FROM (
125 WITH RECURSIVE t(n) AS (
126 SELECT 1 UNION ALL SELECT n + 1 FROM t WHERE n < 100
128 SELECT * FROM t WHERE n < 50000
129 ) AS t WHERE n < 100);
131 -- use same CTE twice at different subquery levels
133 SELECT hundred, sum(ten) FROM tenk1 GROUP BY hundred
135 SELECT count(*) FROM q1 WHERE y > (SELECT sum(y)/100 FROM q1 qsub);
138 CREATE TEMPORARY VIEW vsubdepartment AS
139 WITH RECURSIVE subdepartment AS
141 -- non recursive term
142 SELECT * FROM department WHERE name = 'A'
145 SELECT d.* FROM department AS d, subdepartment AS sd
146 WHERE d.parent_department = sd.id
148 SELECT * FROM subdepartment;
150 SELECT * FROM vsubdepartment ORDER BY name;
152 -- Check reverse listing
153 SELECT pg_get_viewdef('vsubdepartment'::regclass);
154 SELECT pg_get_viewdef('vsubdepartment'::regclass, true);
156 -- recursive term has sub-UNION
157 WITH RECURSIVE t(i,j) AS (
160 SELECT t2.i, t.j+1 FROM
161 (SELECT 2 AS i UNION ALL SELECT 3 AS i) AS t2
162 JOIN t ON (t2.i = t.i+1))
167 -- different tree example
169 CREATE TEMPORARY TABLE tree(
170 id INTEGER PRIMARY KEY,
171 parent_id INTEGER REFERENCES tree(id)
175 VALUES (1, NULL), (2, 1), (3,1), (4,2), (5,2), (6,2), (7,3), (8,3),
176 (9,4), (10,4), (11,7), (12,7), (13,7), (14, 9), (15,11), (16,11);
179 -- get all paths from "second level" nodes to leaf nodes
181 WITH RECURSIVE t(id, path) AS (
182 VALUES(1,ARRAY[]::integer[])
184 SELECT tree.id, t.path || tree.id
185 FROM tree JOIN t ON (tree.parent_id = t.id)
187 SELECT t1.*, t2.* FROM t AS t1 JOIN t AS t2 ON
188 (t1.path[1] = t2.path[1] AND
189 array_upper(t1.path,1) = 1 AND
190 array_upper(t2.path,1) > 1)
191 ORDER BY t1.id, t2.id;
194 WITH RECURSIVE t(id, path) AS (
195 VALUES(1,ARRAY[]::integer[])
197 SELECT tree.id, t.path || tree.id
198 FROM tree JOIN t ON (tree.parent_id = t.id)
200 SELECT t1.id, count(t2.*) FROM t AS t1 JOIN t AS t2 ON
201 (t1.path[1] = t2.path[1] AND
202 array_upper(t1.path,1) = 1 AND
203 array_upper(t2.path,1) > 1)
208 -- test multiple WITH queries
211 y (id) AS (VALUES (1)),
212 x (id) AS (SELECT * FROM y UNION ALL SELECT id+1 FROM x WHERE id < 5)
215 -- forward reference OK
217 x(id) AS (SELECT * FROM y UNION ALL SELECT id+1 FROM x WHERE id < 5),
218 y(id) AS (values (1))
223 (VALUES (1) UNION ALL SELECT id+1 FROM x WHERE id < 5),
225 (VALUES (1) UNION ALL SELECT id+1 FROM y WHERE id < 10)
226 SELECT y.*, x.* FROM y LEFT JOIN x USING (id);
230 (VALUES (1) UNION ALL SELECT id+1 FROM x WHERE id < 5),
232 (VALUES (1) UNION ALL SELECT id+1 FROM x WHERE id < 10)
233 SELECT y.*, x.* FROM y LEFT JOIN x USING (id);
237 (SELECT 1 UNION ALL SELECT id+1 FROM x WHERE id < 3 ),
239 (SELECT * FROM x UNION ALL SELECT * FROM x),
241 (SELECT * FROM x UNION ALL SELECT id+1 FROM z WHERE id < 10)
246 (SELECT 1 UNION ALL SELECT id+1 FROM x WHERE id < 3 ),
248 (SELECT * FROM x UNION ALL SELECT * FROM x),
250 (SELECT * FROM y UNION ALL SELECT id+1 FROM z WHERE id < 10)
257 -- UNION (should be supported someday)
258 WITH RECURSIVE x(n) AS (SELECT 1 UNION SELECT n+1 FROM x)
262 WITH RECURSIVE x(n) AS (SELECT 1 INTERSECT SELECT n+1 FROM x)
265 WITH RECURSIVE x(n) AS (SELECT 1 INTERSECT ALL SELECT n+1 FROM x)
269 WITH RECURSIVE x(n) AS (SELECT 1 EXCEPT SELECT n+1 FROM x)
272 WITH RECURSIVE x(n) AS (SELECT 1 EXCEPT ALL SELECT n+1 FROM x)
275 -- no non-recursive term
276 WITH RECURSIVE x(n) AS (SELECT n FROM x)
279 -- recursive term in the left hand side (strictly speaking, should allow this)
280 WITH RECURSIVE x(n) AS (SELECT n FROM x UNION ALL SELECT 1)
283 CREATE TEMPORARY TABLE y (a INTEGER);
284 INSERT INTO y SELECT generate_series(1, 10);
288 WITH RECURSIVE x(n) AS (SELECT a FROM y WHERE a = 1
290 SELECT x.n+1 FROM y LEFT JOIN x ON x.n = y.a WHERE n < 10)
294 WITH RECURSIVE x(n) AS (SELECT a FROM y WHERE a = 1
296 SELECT x.n+1 FROM x RIGHT JOIN y ON x.n = y.a WHERE n < 10)
300 WITH RECURSIVE x(n) AS (SELECT a FROM y WHERE a = 1
302 SELECT x.n+1 FROM x FULL JOIN y ON x.n = y.a WHERE n < 10)
306 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x
307 WHERE n IN (SELECT * FROM x))
310 -- aggregate functions
311 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT count(*) FROM x)
314 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT sum(n) FROM x)
318 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x ORDER BY 1)
322 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x LIMIT 10 OFFSET 1)
326 WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x FOR UPDATE)
329 -- target list has a recursive query name
330 WITH RECURSIVE x(id) AS (values (1)
332 SELECT (SELECT * FROM x) FROM x WHERE id < 5
335 -- mutual recursive query (not implemented)
337 x (id) AS (SELECT 1 UNION ALL SELECT id+1 FROM y WHERE id < 5),
338 y (id) AS (SELECT 1 UNION ALL SELECT id+1 FROM x WHERE id < 5)
341 -- non-linear recursion is not allowed
342 WITH RECURSIVE foo(i) AS
345 (SELECT i+1 FROM foo WHERE i < 10
347 SELECT i+1 FROM foo WHERE i < 5)
350 WITH RECURSIVE foo(i) AS
354 (SELECT i+1 FROM foo WHERE i < 10
356 SELECT i+1 FROM foo WHERE i < 5) AS t
359 WITH RECURSIVE foo(i) AS
362 (SELECT i+1 FROM foo WHERE i < 10
364 SELECT i+1 FROM foo WHERE i < 5)
367 WITH RECURSIVE foo(i) AS
370 (SELECT i+1 FROM foo WHERE i < 10
372 SELECT i+1 FROM foo WHERE i < 5)
375 -- Wrong type induced from non-recursive term
376 WITH RECURSIVE foo(i) AS
377 (SELECT i FROM (VALUES(1),(2)) t(i)
379 SELECT (i+1)::numeric(10,0) FROM foo WHERE i < 10)
382 -- rejects different typmod, too (should we allow this?)
383 WITH RECURSIVE foo(i) AS
384 (SELECT i::numeric(3,0) FROM (VALUES(1),(2)) t(i)
386 SELECT (i+1)::numeric(10,0) FROM foo WHERE i < 10)