mirror of https://github.com/citusdata/citus.git
1080 lines
28 KiB
Plaintext
1080 lines
28 KiB
Plaintext
-- Test the basic CTE functionality and expected error messages
|
|
SET search_path TO 'with_basics';
|
|
SET citus.coordinator_aggregation_strategy TO 'disabled';
|
|
CREATE TYPE with_basics.xy AS (x int, y int);
|
|
-- CTEs in FROM should work
|
|
WITH cte AS (
|
|
SELECT user_id, value_2 from users_table WHERE user_id IN (1, 2) ORDER BY 1,2 LIMIT 5
|
|
)
|
|
SELECT * FROM cte;
|
|
user_id | value_2
|
|
---------------------------------------------------------------------
|
|
1 | 0
|
|
1 | 2
|
|
1 | 3
|
|
1 | 3
|
|
1 | 4
|
|
(5 rows)
|
|
|
|
-- CTEs in WHERE should work
|
|
WITH cte AS (
|
|
SELECT user_id from users_table ORDER BY user_id DESC LIMIT 10
|
|
)
|
|
SELECT
|
|
value_2
|
|
FROM
|
|
users_table
|
|
WHERE
|
|
user_id IN (SELECT user_id FROM users_table)
|
|
ORDER BY
|
|
value_2
|
|
LIMIT
|
|
5;
|
|
value_2
|
|
---------------------------------------------------------------------
|
|
0
|
|
0
|
|
0
|
|
0
|
|
0
|
|
(5 rows)
|
|
|
|
-- nested CTEs should work
|
|
WITH cte_1 AS (
|
|
WITH cte_1_1 AS (
|
|
SELECT user_id, value_2 from users_table WHERE user_id IN (1, 2) ORDER BY 2 LIMIT 5
|
|
),
|
|
cte_1_2 AS (
|
|
SELECT max(user_id) AS user_id FROM cte_1_1
|
|
)
|
|
SELECT user_id FROM cte_1_2 ORDER BY user_id
|
|
)
|
|
SELECT value_2 FROM users_table WHERE user_id IN (SELECT user_id FROM cte_1) ORDER BY value_2 LIMIT 1;
|
|
value_2
|
|
---------------------------------------------------------------------
|
|
0
|
|
(1 row)
|
|
|
|
-- Mix of FROM/WHERE queries
|
|
WITH cte_from AS (
|
|
SELECT max(user_id) AS user_id, value_2, value_1 FROM users_table GROUP BY value_2, value_1
|
|
),
|
|
cte_where AS (
|
|
SELECT value_2 FROM events_table
|
|
)
|
|
SELECT
|
|
*
|
|
FROM
|
|
(SELECT max(user_id), max(value_2) AS value_2 FROM cte_from GROUP BY value_1) f
|
|
WHERE
|
|
value_2 IN (SELECT * FROM cte_where)
|
|
ORDER BY
|
|
1, 2
|
|
LIMIT
|
|
5;
|
|
max | value_2
|
|
---------------------------------------------------------------------
|
|
5 | 5
|
|
6 | 5
|
|
6 | 5
|
|
6 | 5
|
|
6 | 5
|
|
(5 rows)
|
|
|
|
-- CTE in subquery recursively planned
|
|
SELECT user_id FROM (
|
|
WITH cte AS (
|
|
SELECT user_id, value_2 from users_table WHERE user_id IN (1, 2) ORDER BY 2 LIMIT 5
|
|
)
|
|
SELECT user_id FROM cte WHERE value_2 > 0
|
|
) a ORDER BY 1 LIMIT 3;
|
|
user_id
|
|
---------------------------------------------------------------------
|
|
2
|
|
2
|
|
2
|
|
(3 rows)
|
|
|
|
-- CTE outside of FROM/WHERE errors
|
|
WITH cte AS (
|
|
SELECT user_id FROM users_table WHERE value_2 IN (1, 2)
|
|
)
|
|
SELECT (SELECT * FROM cte);
|
|
ERROR: more than one row returned by a subquery used as an expression
|
|
WITH cte_basic AS (
|
|
SELECT user_id FROM users_table WHERE user_id = 1 LIMIT 1
|
|
)
|
|
SELECT
|
|
(SELECT user_id FROM cte_basic), user_id
|
|
FROM
|
|
users_table
|
|
ORDER BY 1,2
|
|
LIMIT 1;
|
|
user_id | user_id
|
|
---------------------------------------------------------------------
|
|
1 | 1
|
|
(1 row)
|
|
|
|
-- single-row sublink is acceptable when there is no FROM
|
|
WITH cte AS (
|
|
SELECT user_id FROM users_table WHERE value_2 IN (1, 2)
|
|
)
|
|
SELECT (SELECT * FROM cte ORDER BY 1 LIMIT 1);
|
|
user_id
|
|
---------------------------------------------------------------------
|
|
1
|
|
(1 row)
|
|
|
|
-- group by partition column
|
|
WITH series AS (
|
|
SELECT s AS once, s*2 AS twice FROM generate_series(1,10) s
|
|
)
|
|
SELECT user_id, count(*)
|
|
FROM
|
|
users_table
|
|
JOIN
|
|
series ON (user_id = once)
|
|
GROUP BY
|
|
user_id
|
|
ORDER BY
|
|
1, 2
|
|
LIMIT 5;
|
|
user_id | count
|
|
---------------------------------------------------------------------
|
|
1 | 7
|
|
2 | 18
|
|
3 | 17
|
|
4 | 23
|
|
5 | 26
|
|
(5 rows)
|
|
|
|
-- group by non-partition column
|
|
WITH series AS (
|
|
SELECT s AS once, s*2 AS twice FROM generate_series(1,10) s
|
|
)
|
|
SELECT
|
|
twice, min(user_id)
|
|
FROM
|
|
users_table
|
|
JOIN
|
|
series ON (user_id = once)
|
|
GROUP BY
|
|
twice
|
|
HAVING
|
|
twice > 5
|
|
ORDER BY
|
|
1, 2
|
|
LIMIT 5;
|
|
twice | min
|
|
---------------------------------------------------------------------
|
|
6 | 3
|
|
8 | 4
|
|
10 | 5
|
|
12 | 6
|
|
(4 rows)
|
|
|
|
-- distinct in subquery on CTE
|
|
WITH one_user AS (
|
|
SELECT user_id from users_table WHERE user_id = 1
|
|
)
|
|
SELECT
|
|
user_id
|
|
FROM
|
|
users_table
|
|
WHERE
|
|
value_2 IN (SELECT DISTINCT user_id FROM one_user)
|
|
ORDER BY
|
|
user_id
|
|
LIMIT
|
|
1;
|
|
user_id
|
|
---------------------------------------------------------------------
|
|
2
|
|
(1 row)
|
|
|
|
-- having in subquery on CTE
|
|
WITH one_user AS (
|
|
SELECT user_id from users_table WHERE user_id = 1
|
|
)
|
|
SELECT
|
|
user_id
|
|
FROM
|
|
users_table
|
|
WHERE
|
|
value_2 IN (SELECT user_id FROM one_user GROUP BY user_id HAVING count(*) > 0)
|
|
ORDER BY
|
|
user_id
|
|
LIMIT
|
|
1;
|
|
user_id
|
|
---------------------------------------------------------------------
|
|
2
|
|
(1 row)
|
|
|
|
-- aggregate in subquery on CTE
|
|
WITH top_users AS (
|
|
SELECT user_id, value_2 FROM users_table ORDER BY user_id DESC LIMIT 10
|
|
)
|
|
SELECT
|
|
user_id
|
|
FROM
|
|
(SELECT min(user_id) AS user_id FROM top_users) top_users
|
|
JOIN
|
|
users_table USING (user_id);
|
|
user_id
|
|
---------------------------------------------------------------------
|
|
6
|
|
6
|
|
6
|
|
6
|
|
6
|
|
6
|
|
6
|
|
6
|
|
6
|
|
6
|
|
(10 rows)
|
|
|
|
-- column aliases in CTE
|
|
WITH top_ten(id, val1) AS (
|
|
SELECT user_id, value_1 FROM users_table ORDER BY value_1 DESC, user_id DESC LIMIT 10
|
|
)
|
|
SELECT * FROM top_ten;
|
|
id | val1
|
|
---------------------------------------------------------------------
|
|
6 | 5
|
|
6 | 5
|
|
5 | 5
|
|
5 | 5
|
|
5 | 5
|
|
4 | 5
|
|
4 | 5
|
|
3 | 5
|
|
1 | 5
|
|
5 | 4
|
|
(10 rows)
|
|
|
|
-- verify old name is not valid anymore
|
|
WITH top_ten(id, val1) AS (
|
|
SELECT user_id, value_1 FROM users_table ORDER BY value_1 DESC, user_id DESC LIMIT 10
|
|
)
|
|
SELECT * FROM top_ten ORDER BY user_id DESC;
|
|
ERROR: column "user_id" does not exist
|
|
-- verify original name is used if alias is missing
|
|
WITH top_ten(id) AS (
|
|
SELECT user_id, value_1 FROM users_table ORDER BY value_1 DESC, user_id DESC LIMIT 10
|
|
)
|
|
SELECT * FROM top_ten ORDER BY value_1 DESC;
|
|
id | value_1
|
|
---------------------------------------------------------------------
|
|
6 | 5
|
|
6 | 5
|
|
5 | 5
|
|
5 | 5
|
|
5 | 5
|
|
4 | 5
|
|
4 | 5
|
|
3 | 5
|
|
1 | 5
|
|
5 | 4
|
|
(10 rows)
|
|
|
|
-- computed targets from columns also work
|
|
WITH top_ten(id, val, val_mul, val_sum) AS (
|
|
SELECT user_id, value_1, value_1*2, value_1 + value_2 FROM users_table ORDER BY value_1 DESC, user_id DESC, value_2 DESC LIMIT 10
|
|
)
|
|
SELECT * FROM top_ten ORDER BY id DESC, val_mul DESC, (val_sum + 1) DESC;
|
|
id | val | val_mul | val_sum
|
|
---------------------------------------------------------------------
|
|
6 | 5 | 10 | 7
|
|
6 | 5 | 10 | 5
|
|
5 | 5 | 10 | 10
|
|
5 | 5 | 10 | 7
|
|
5 | 5 | 10 | 6
|
|
5 | 4 | 8 | 7
|
|
4 | 5 | 10 | 9
|
|
4 | 5 | 10 | 8
|
|
3 | 5 | 10 | 10
|
|
1 | 5 | 10 | 9
|
|
(10 rows)
|
|
|
|
-- computed targets from columns in outer query
|
|
WITH top_ten(id, val, val_mul, val_sum) AS (
|
|
SELECT user_id, value_1, value_1*2, value_1 + value_2 FROM users_table ORDER BY value_1 DESC, value_2 DESC, user_id DESC LIMIT 10
|
|
)
|
|
SELECT id, val, id * val, val_sum * 2, val_sum + val_sum FROM top_ten ORDER BY 1 DESC, 2 DESC, 3 DESC, 4 DESC;
|
|
id | val | ?column? | ?column? | ?column?
|
|
---------------------------------------------------------------------
|
|
6 | 5 | 30 | 14 | 14
|
|
6 | 5 | 30 | 10 | 10
|
|
5 | 5 | 25 | 20 | 20
|
|
5 | 5 | 25 | 14 | 14
|
|
5 | 5 | 25 | 12 | 12
|
|
4 | 5 | 20 | 18 | 18
|
|
4 | 5 | 20 | 16 | 16
|
|
4 | 4 | 16 | 18 | 18
|
|
3 | 5 | 15 | 20 | 20
|
|
1 | 5 | 5 | 18 | 18
|
|
(10 rows)
|
|
|
|
-- computed targets from columns and group by outside
|
|
WITH top_ten(id, val, val_mul, val_sum) AS (
|
|
SELECT user_id, value_1, value_1*2, value_1 + value_2 FROM users_table ORDER BY value_1 DESC, user_id DESC
|
|
)
|
|
SELECT id, count(*), avg(val), max(val_mul), min(val_sum) FROM top_ten
|
|
GROUP BY id
|
|
ORDER BY 2 DESC, 1 DESC;
|
|
id | count | avg | max | min
|
|
---------------------------------------------------------------------
|
|
5 | 26 | 2.6538461538461538 | 10 | 2
|
|
4 | 23 | 2.7391304347826087 | 10 | 0
|
|
2 | 18 | 2.3333333333333333 | 8 | 1
|
|
3 | 17 | 2.3529411764705882 | 10 | 2
|
|
6 | 10 | 2.1000000000000000 | 10 | 0
|
|
1 | 7 | 3.2857142857142857 | 10 | 4
|
|
(6 rows)
|
|
|
|
-- FOR UPDATE in subquery on CTE
|
|
WITH top_users AS (
|
|
SELECT user_id, value_2 FROM users_table ORDER BY user_id DESC LIMIT 10
|
|
)
|
|
SELECT
|
|
user_id
|
|
FROM
|
|
(SELECT user_id FROM top_users FOR UPDATE) top_users
|
|
JOIN
|
|
users_table USING (user_id)
|
|
ORDER BY
|
|
user_id
|
|
LIMIT
|
|
5;
|
|
user_id
|
|
---------------------------------------------------------------------
|
|
6
|
|
6
|
|
6
|
|
6
|
|
6
|
|
(5 rows)
|
|
|
|
-- LIMIT in subquery on CTE
|
|
WITH top_users AS (
|
|
SELECT user_id, value_2 FROM users_table ORDER BY user_id DESC LIMIT 10
|
|
)
|
|
SELECT
|
|
user_id
|
|
FROM
|
|
(SELECT user_id FROM top_users LIMIT 5) top_users
|
|
JOIN
|
|
users_table USING (user_id)
|
|
ORDER BY
|
|
user_id
|
|
LIMIT
|
|
5;
|
|
user_id
|
|
---------------------------------------------------------------------
|
|
6
|
|
6
|
|
6
|
|
6
|
|
6
|
|
(5 rows)
|
|
|
|
-- OFFSET in subquery on CTE
|
|
WITH top_users AS (
|
|
SELECT user_id, value_2 FROM users_table ORDER BY user_id DESC LIMIT 10
|
|
)
|
|
SELECT
|
|
user_id
|
|
FROM
|
|
(SELECT user_id FROM top_users OFFSET 5) top_users
|
|
JOIN
|
|
users_table USING (user_id)
|
|
ORDER BY
|
|
user_id
|
|
LIMIT
|
|
5;
|
|
user_id
|
|
---------------------------------------------------------------------
|
|
6
|
|
6
|
|
6
|
|
6
|
|
6
|
|
(5 rows)
|
|
|
|
-- non-equi joins in CTE are supported if accompanied with an equi-join
|
|
WITH top_users AS (
|
|
SELECT DISTINCT e.user_id FROM users_table u JOIN events_table e ON (u.user_id = e.user_id AND u.value_1 > e.value_2)
|
|
)
|
|
SELECT
|
|
user_id
|
|
FROM
|
|
(SELECT user_id FROM top_users WHERE user_id > 5) top_users
|
|
JOIN
|
|
users_table USING (user_id)
|
|
ORDER BY
|
|
user_id
|
|
LIMIT
|
|
5;
|
|
user_id
|
|
---------------------------------------------------------------------
|
|
6
|
|
6
|
|
6
|
|
6
|
|
6
|
|
(5 rows)
|
|
|
|
-- Join can be supported with another CTE
|
|
WITH events_table AS (
|
|
SELECT * FROM events_table
|
|
),
|
|
top_users AS (
|
|
SELECT DISTINCT e.user_id FROM users_table u JOIN events_table e ON (u.user_id = e.user_id AND u.value_1 > e.value_2)
|
|
)
|
|
SELECT
|
|
user_id
|
|
FROM
|
|
(SELECT user_id FROM top_users WHERE user_id > 5) top_users
|
|
JOIN
|
|
users_table USING (user_id)
|
|
ORDER BY
|
|
user_id
|
|
LIMIT
|
|
5;
|
|
user_id
|
|
---------------------------------------------------------------------
|
|
6
|
|
6
|
|
6
|
|
6
|
|
6
|
|
(5 rows)
|
|
|
|
-- Window functions in CTE
|
|
WITH top_users AS (
|
|
SELECT row_number() OVER(), user_id FROM users_table ORDER BY user_id DESC LIMIT 10
|
|
)
|
|
SELECT
|
|
user_id
|
|
FROM
|
|
(SELECT user_id FROM top_users WHERE user_id > 5) top_users
|
|
JOIN
|
|
users_table USING (user_id)
|
|
ORDER BY
|
|
user_id
|
|
LIMIT
|
|
5;
|
|
user_id
|
|
---------------------------------------------------------------------
|
|
6
|
|
6
|
|
6
|
|
6
|
|
6
|
|
(5 rows)
|
|
|
|
-- Window functions that partition by the distribution column in subqueries in CTEs are ok
|
|
WITH top_users AS
|
|
(SELECT *
|
|
FROM
|
|
(SELECT row_number() OVER(PARTITION BY user_id) AS row_number,
|
|
user_id
|
|
FROM users_table) AS foo
|
|
)
|
|
SELECT user_id
|
|
FROM
|
|
(SELECT user_id
|
|
FROM top_users
|
|
WHERE row_number > 5) top_users
|
|
JOIN
|
|
users_table USING (user_id)
|
|
ORDER BY
|
|
user_id
|
|
LIMIT
|
|
5;
|
|
user_id
|
|
---------------------------------------------------------------------
|
|
1
|
|
1
|
|
1
|
|
1
|
|
1
|
|
(5 rows)
|
|
|
|
-- Unsupported aggregate in CTE
|
|
WITH top_users AS (
|
|
SELECT array_agg(user_id ORDER BY value_2) user_ids FROM users_table
|
|
)
|
|
SELECT
|
|
user_id
|
|
FROM
|
|
(SELECT unnest(user_ids) user_id FROM top_users) top_users
|
|
JOIN
|
|
users_table USING (user_id)
|
|
ORDER BY
|
|
user_id
|
|
LIMIT
|
|
5;
|
|
ERROR: array_agg with order by is unsupported
|
|
-- array_agg in CTE
|
|
WITH top_users AS (
|
|
SELECT array_agg(user_id) user_ids FROM users_table
|
|
)
|
|
SELECT
|
|
user_id
|
|
FROM
|
|
(SELECT unnest(user_ids) user_id FROM top_users) top_users
|
|
JOIN
|
|
users_table USING (user_id)
|
|
ORDER BY
|
|
user_id
|
|
LIMIT
|
|
5;
|
|
user_id
|
|
---------------------------------------------------------------------
|
|
1
|
|
1
|
|
1
|
|
1
|
|
1
|
|
(5 rows)
|
|
|
|
-- composite type array
|
|
WITH top_users AS (
|
|
SELECT array_agg((value_1,value_2)::xy) AS p FROM users_table WHERE user_id % 2 = 0
|
|
)
|
|
SELECT
|
|
e.user_id, sum(y)
|
|
FROM
|
|
(SELECT (unnest(p)).* FROM top_users) tops
|
|
JOIN
|
|
events_table e ON (tops.x = e.user_id)
|
|
GROUP BY
|
|
e.user_id
|
|
ORDER BY
|
|
2 DESC, 1
|
|
LIMIT
|
|
5;
|
|
user_id | sum
|
|
---------------------------------------------------------------------
|
|
3 | 651
|
|
2 | 552
|
|
4 | 544
|
|
5 | 126
|
|
1 | 90
|
|
(5 rows)
|
|
|
|
-- SELECT * FROM (SELECT * FROM cte UNION SELECT * FROM distributed_table) a; should work
|
|
WITH cte AS (
|
|
SELECT * FROM users_table
|
|
)
|
|
SELECT * FROM (
|
|
SELECT * FROM cte UNION (SELECT * FROM events_table)
|
|
) a
|
|
ORDER BY
|
|
1,2,3,4,5,6
|
|
LIMIT
|
|
10;
|
|
user_id | time | value_1 | value_2 | value_3 | value_4
|
|
---------------------------------------------------------------------
|
|
1 | Wed Nov 22 18:49:42.327403 2017 | 3 | 2 | 1 |
|
|
1 | Wed Nov 22 19:03:01.772353 2017 | 4 | 1 | 2 |
|
|
1 | Wed Nov 22 19:07:03.846437 2017 | 1 | 2 | 5 |
|
|
1 | Wed Nov 22 20:56:21.122638 2017 | 2 | 4 | 4 |
|
|
1 | Wed Nov 22 21:06:57.457147 2017 | 4 | 3 | 2 |
|
|
1 | Wed Nov 22 21:47:04.188168 2017 | 4 | 2 | 0 |
|
|
1 | Wed Nov 22 22:51:43.132261 2017 | 4 | 0 | 3 |
|
|
1 | Wed Nov 22 23:22:09.957743 2017 | 1 | 1 | 1 |
|
|
1 | Thu Nov 23 00:42:37.237615 2017 | 2 | 4 | 3 |
|
|
1 | Thu Nov 23 02:59:23.620864 2017 | 4 | 5 | 4 |
|
|
(10 rows)
|
|
|
|
SELECT * FROM (
|
|
SELECT * FROM (WITH cte AS (
|
|
SELECT * FROM users_table
|
|
)
|
|
SELECT * FROM cte
|
|
)b UNION (SELECT * FROM events_table)) a
|
|
ORDER BY
|
|
1,2,3,4,5,6
|
|
LIMIT
|
|
10;
|
|
user_id | time | value_1 | value_2 | value_3 | value_4
|
|
---------------------------------------------------------------------
|
|
1 | Wed Nov 22 18:49:42.327403 2017 | 3 | 2 | 1 |
|
|
1 | Wed Nov 22 19:03:01.772353 2017 | 4 | 1 | 2 |
|
|
1 | Wed Nov 22 19:07:03.846437 2017 | 1 | 2 | 5 |
|
|
1 | Wed Nov 22 20:56:21.122638 2017 | 2 | 4 | 4 |
|
|
1 | Wed Nov 22 21:06:57.457147 2017 | 4 | 3 | 2 |
|
|
1 | Wed Nov 22 21:47:04.188168 2017 | 4 | 2 | 0 |
|
|
1 | Wed Nov 22 22:51:43.132261 2017 | 4 | 0 | 3 |
|
|
1 | Wed Nov 22 23:22:09.957743 2017 | 1 | 1 | 1 |
|
|
1 | Thu Nov 23 00:42:37.237615 2017 | 2 | 4 | 3 |
|
|
1 | Thu Nov 23 02:59:23.620864 2017 | 4 | 5 | 4 |
|
|
(10 rows)
|
|
|
|
-- SELECT * FROM (SELECT * FROM cte UNION SELECT * FROM cte) a; should work
|
|
WITH cte AS (
|
|
SELECT * FROM users_table WHERE user_id IN (1, 2)
|
|
)
|
|
SELECT
|
|
*
|
|
FROM
|
|
(SELECT * FROM cte UNION (SELECT * FROM cte)) a
|
|
ORDER BY
|
|
1,2,3,4,5,6
|
|
LIMIT
|
|
5;
|
|
user_id | time | value_1 | value_2 | value_3 | value_4
|
|
---------------------------------------------------------------------
|
|
1 | Wed Nov 22 22:51:43.132261 2017 | 4 | 0 | 3 |
|
|
1 | Thu Nov 23 03:32:50.803031 2017 | 3 | 2 | 1 |
|
|
1 | Thu Nov 23 09:26:42.145043 2017 | 1 | 3 | 3 |
|
|
1 | Thu Nov 23 11:11:24.40789 2017 | 3 | 4 | 0 |
|
|
1 | Thu Nov 23 11:44:57.515981 2017 | 4 | 3 | 4 |
|
|
(5 rows)
|
|
|
|
WITH cte AS (
|
|
SELECT * FROM users_table WHERE user_id IN (1, 2) ORDER BY 1,2,3 LIMIT 5
|
|
),
|
|
cte_2 AS (
|
|
SELECT * FROM users_table WHERE user_id IN (3, 4) ORDER BY 1,2,3 LIMIT 5
|
|
)
|
|
SELECT * FROM cte UNION ALL SELECT * FROM cte_2;
|
|
user_id | time | value_1 | value_2 | value_3 | value_4
|
|
---------------------------------------------------------------------
|
|
1 | Wed Nov 22 22:51:43.132261 2017 | 4 | 0 | 3 |
|
|
1 | Thu Nov 23 03:32:50.803031 2017 | 3 | 2 | 1 |
|
|
1 | Thu Nov 23 09:26:42.145043 2017 | 1 | 3 | 3 |
|
|
1 | Thu Nov 23 11:11:24.40789 2017 | 3 | 4 | 0 |
|
|
1 | Thu Nov 23 11:44:57.515981 2017 | 4 | 3 | 4 |
|
|
3 | Wed Nov 22 18:43:51.450263 2017 | 1 | 1 | 4 |
|
|
3 | Wed Nov 22 20:43:31.008625 2017 | 1 | 3 | 2 |
|
|
3 | Wed Nov 22 23:24:32.080584 2017 | 3 | 2 | 5 |
|
|
3 | Thu Nov 23 00:15:45.610845 2017 | 1 | 1 | 4 |
|
|
3 | Thu Nov 23 03:23:24.702501 2017 | 1 | 2 | 5 |
|
|
(10 rows)
|
|
|
|
-- basic recursive CTE which should all error out
|
|
WITH RECURSIVE basic_recursive(x) AS (
|
|
VALUES (1)
|
|
UNION ALL
|
|
SELECT user_id + 1 FROM users_table JOIN basic_recursive ON (user_id = x) WHERE user_id < 100
|
|
)
|
|
SELECT sum(x) FROM basic_recursive;
|
|
ERROR: recursive CTEs are only supported when they contain a filter on the distribution column
|
|
WITH RECURSIVE basic_recursive AS (
|
|
SELECT -1 as user_id, '2017-11-22 20:16:16.614779'::timestamp, -1, -1, -1, -1
|
|
UNION ALL
|
|
SELECT basic_recursive.* FROM users_table JOIN basic_recursive USING (user_id) WHERE user_id>1
|
|
)
|
|
SELECT * FROM basic_recursive ORDER BY user_id LIMIT 1;
|
|
ERROR: recursive CTEs are only supported when they contain a filter on the distribution column
|
|
-- basic_recursive in FROM should error out
|
|
SELECT
|
|
*
|
|
FROM
|
|
(WITH RECURSIVE basic_recursive AS (
|
|
SELECT -1 as user_id, '2017-11-22 20:16:16.614779'::timestamp, -1, -1, -1, -1
|
|
UNION ALL
|
|
SELECT basic_recursive.* FROM users_table JOIN basic_recursive USING (user_id) WHERE user_id>1
|
|
)
|
|
SELECT * FROM basic_recursive ORDER BY user_id LIMIT 1) cte_rec;
|
|
ERROR: recursive CTEs are only supported when they contain a filter on the distribution column
|
|
-- basic_recursive in WHERE with UNION ALL
|
|
SELECT
|
|
*
|
|
FROM
|
|
users_table
|
|
WHERE
|
|
user_id in
|
|
(WITH RECURSIVE basic_recursive AS (
|
|
SELECT -1 as user_id
|
|
UNION ALL
|
|
SELECT basic_recursive.* FROM users_table JOIN basic_recursive USING (user_id) WHERE user_id>1
|
|
)
|
|
SELECT * FROM basic_recursive ORDER BY user_id LIMIT 1);
|
|
ERROR: recursive CTEs are only supported when they contain a filter on the distribution column
|
|
-- one recursive one regular CTE should error out
|
|
WITH RECURSIVE basic_recursive(x) AS(
|
|
VALUES (1)
|
|
UNION ALL
|
|
SELECT user_id + 1 FROM users_table JOIN basic_recursive ON (user_id = x) WHERE user_id < 100
|
|
),
|
|
basic AS (
|
|
SELECT count(user_id) FROM users_table
|
|
)
|
|
SELECT x FROM basic, basic_recursive;
|
|
ERROR: recursive CTEs are only supported when they contain a filter on the distribution column
|
|
-- one recursive one regular which SELECTs from the recursive CTE under a simple SELECT
|
|
WITH RECURSIVE basic_recursive(x) AS(
|
|
VALUES (1)
|
|
UNION ALL
|
|
SELECT user_id + 1 FROM users_table JOIN basic_recursive ON (user_id = x) WHERE user_id < 100
|
|
),
|
|
basic AS (
|
|
SELECT count(x) FROM basic_recursive
|
|
)
|
|
SELECT * FROM basic;
|
|
ERROR: recursive CTEs are only supported when they contain a filter on the distribution column
|
|
-- recursive CTE in a NESTED manner
|
|
WITH regular_cte AS (
|
|
WITH regular_2 AS (
|
|
WITH RECURSIVE recursive(x) AS (
|
|
VALUES (1)
|
|
UNION ALL
|
|
SELECT user_id + 1 FROM users_table JOIN recursive ON (user_id = x) WHERE user_id < 100
|
|
)
|
|
SELECT * FROM recursive
|
|
)
|
|
SELECT * FROM regular_2
|
|
)
|
|
SELECT * FROM regular_cte;
|
|
ERROR: recursive CTEs are only supported when they contain a filter on the distribution column
|
|
-- CTEs should work with VIEWs as well
|
|
CREATE VIEW basic_view AS
|
|
SELECT * FROM users_table;
|
|
CREATE VIEW cte_view AS
|
|
WITH cte AS (
|
|
SELECT * FROM users_table
|
|
)
|
|
SELECT user_id, max(value_1) as value_1 FROM cte GROUP BY 1;
|
|
WITH cte_user AS (
|
|
SELECT basic_view.user_id,events_table.value_2 FROM basic_view join events_table on (basic_view.user_id = events_table.user_id)
|
|
)
|
|
SELECT user_id, sum(value_2) FROM cte_user GROUP BY 1 ORDER BY 1, 2;
|
|
user_id | sum
|
|
---------------------------------------------------------------------
|
|
1 | 294
|
|
2 | 1026
|
|
3 | 782
|
|
4 | 943
|
|
5 | 806
|
|
6 | 220
|
|
(6 rows)
|
|
|
|
SELECT * FROM cte_view ORDER BY 1, 2 LIMIT 5;
|
|
user_id | value_1
|
|
---------------------------------------------------------------------
|
|
1 | 5
|
|
2 | 4
|
|
3 | 5
|
|
4 | 5
|
|
5 | 5
|
|
(5 rows)
|
|
|
|
WITH cte_user_with_view AS
|
|
(
|
|
SELECT * FROM cte_view WHERE user_id < 3
|
|
)
|
|
SELECT user_id, value_1 FROM cte_user_with_view ORDER BY 1, 2 LIMIT 10 OFFSET 2;
|
|
user_id | value_1
|
|
---------------------------------------------------------------------
|
|
(0 rows)
|
|
|
|
-- test case added for https://github.com/citusdata/citus/issues/3565
|
|
CREATE TABLE test_cte
|
|
(
|
|
user_id varchar
|
|
);
|
|
INSERT INTO test_cte
|
|
SELECT *
|
|
FROM (VALUES ('1'), ('1'), ('2'), ('2'), ('3'), ('4'), ('5'), ('6'), ('7'), ('8')) AS foo;
|
|
CREATE TABLE test_cte_distributed
|
|
(
|
|
user_id varchar
|
|
);
|
|
SELECT *
|
|
FROM create_distributed_table('test_cte_distributed', 'user_id');
|
|
create_distributed_table
|
|
---------------------------------------------------------------------
|
|
|
|
(1 row)
|
|
|
|
INSERT INTO test_cte_distributed
|
|
SELECT *
|
|
FROM (VALUES ('1'), ('3'), ('3'), ('5'), ('8')) AS foo;
|
|
WITH distinct_undistribured AS (
|
|
SELECT DISTINCT user_id
|
|
FROM test_cte
|
|
),
|
|
exsist_in_distributed AS (
|
|
SELECT DISTINCT user_id
|
|
FROM test_cte_distributed
|
|
WHERE EXISTS(SELECT *
|
|
FROM distinct_undistribured
|
|
WHERE distinct_undistribured.user_id = test_cte_distributed.user_id)
|
|
)
|
|
SELECT
|
|
*
|
|
FROM
|
|
distinct_undistribured LEFT JOIN exsist_in_distributed
|
|
ON distinct_undistribured.user_id = exsist_in_distributed.user_id
|
|
ORDER BY 2 DESC, 1 DESC;
|
|
user_id | user_id
|
|
---------------------------------------------------------------------
|
|
7 |
|
|
6 |
|
|
4 |
|
|
2 |
|
|
8 | 8
|
|
5 | 5
|
|
3 | 3
|
|
1 | 1
|
|
(8 rows)
|
|
|
|
-- same query, but the CTE is written as subquery
|
|
WITH distinct_undistribured AS
|
|
(SELECT DISTINCT user_id
|
|
FROM test_cte)
|
|
SELECT *
|
|
FROM distinct_undistribured
|
|
LEFT JOIN
|
|
(SELECT DISTINCT user_id
|
|
FROM test_cte_distributed
|
|
WHERE EXISTS
|
|
(SELECT *
|
|
FROM distinct_undistribured
|
|
WHERE distinct_undistribured.user_id = test_cte_distributed.user_id)) exsist_in_distributed
|
|
ON distinct_undistribured.user_id = exsist_in_distributed.user_id
|
|
ORDER BY 2 DESC, 1 DESC;
|
|
user_id | user_id
|
|
---------------------------------------------------------------------
|
|
7 |
|
|
6 |
|
|
4 |
|
|
2 |
|
|
8 | 8
|
|
5 | 5
|
|
3 | 3
|
|
1 | 1
|
|
(8 rows)
|
|
|
|
-- similar query as the above, but this time
|
|
-- use NOT EXITS, which is pretty common struct
|
|
WITH distinct_undistribured AS
|
|
(SELECT DISTINCT user_id
|
|
FROM test_cte)
|
|
SELECT *
|
|
FROM distinct_undistribured
|
|
LEFT JOIN
|
|
(SELECT DISTINCT user_id
|
|
FROM test_cte_distributed
|
|
WHERE NOT EXISTS
|
|
(SELECT NULL
|
|
FROM distinct_undistribured
|
|
WHERE distinct_undistribured.user_id = test_cte_distributed.user_id)) exsist_in_distributed ON distinct_undistribured.user_id = exsist_in_distributed.user_id
|
|
ORDER BY 1,2;
|
|
user_id | user_id
|
|
---------------------------------------------------------------------
|
|
1 |
|
|
2 |
|
|
3 |
|
|
4 |
|
|
5 |
|
|
6 |
|
|
7 |
|
|
8 |
|
|
(8 rows)
|
|
|
|
-- same NOT EXISTS struct, but with CTE
|
|
-- so should work
|
|
WITH distinct_undistribured AS (
|
|
SELECT DISTINCT user_id
|
|
FROM test_cte
|
|
),
|
|
not_exsist_in_distributed AS (
|
|
SELECT DISTINCT user_id
|
|
FROM test_cte_distributed
|
|
WHERE NOT EXISTS(SELECT NULL
|
|
FROM distinct_undistribured
|
|
WHERE distinct_undistribured.user_id = test_cte_distributed.user_id)
|
|
)
|
|
SELECT
|
|
*
|
|
FROM
|
|
distinct_undistribured LEFT JOIN not_exsist_in_distributed
|
|
ON distinct_undistribured.user_id = not_exsist_in_distributed.user_id
|
|
ORDER BY 2 DESC, 1 DESC;
|
|
user_id | user_id
|
|
---------------------------------------------------------------------
|
|
8 |
|
|
7 |
|
|
6 |
|
|
5 |
|
|
4 |
|
|
3 |
|
|
2 |
|
|
1 |
|
|
(8 rows)
|
|
|
|
-- similar query, but this time the second
|
|
-- part of the query is not inside a CTE
|
|
WITH distinct_undistribured AS (
|
|
SELECT DISTINCT user_id
|
|
FROM test_cte
|
|
)
|
|
SELECT count(*)
|
|
FROM distinct_undistribured
|
|
LEFT JOIN
|
|
(SELECT *,
|
|
random()
|
|
FROM test_cte_distributed d1
|
|
WHERE NOT EXISTS
|
|
(SELECT NULL
|
|
FROM distinct_undistribured d2
|
|
WHERE d1.user_id = d2.user_id )) AS bar USING (user_id);
|
|
count
|
|
---------------------------------------------------------------------
|
|
8
|
|
(1 row)
|
|
|
|
-- should work fine with materialized ctes
|
|
WITH distinct_undistribured AS MATERIALIZED (
|
|
SELECT DISTINCT user_id
|
|
FROM test_cte
|
|
),
|
|
exsist_in_distributed AS MATERIALIZED (
|
|
SELECT DISTINCT user_id
|
|
FROM test_cte_distributed
|
|
WHERE EXISTS(SELECT *
|
|
FROM distinct_undistribured
|
|
WHERE distinct_undistribured.user_id = test_cte_distributed.user_id)
|
|
)
|
|
SELECT
|
|
*
|
|
FROM
|
|
distinct_undistribured LEFT JOIN exsist_in_distributed
|
|
ON distinct_undistribured.user_id = exsist_in_distributed.user_id
|
|
ORDER BY 2 DESC, 1 DESC;
|
|
user_id | user_id
|
|
---------------------------------------------------------------------
|
|
7 |
|
|
6 |
|
|
4 |
|
|
2 |
|
|
8 | 8
|
|
5 | 5
|
|
3 | 3
|
|
1 | 1
|
|
(8 rows)
|
|
|
|
WITH distinct_undistribured AS MATERIALIZED
|
|
(SELECT DISTINCT user_id
|
|
FROM test_cte)
|
|
SELECT *
|
|
FROM distinct_undistribured
|
|
LEFT JOIN
|
|
(SELECT DISTINCT user_id
|
|
FROM test_cte_distributed
|
|
WHERE EXISTS
|
|
(SELECT *
|
|
FROM distinct_undistribured
|
|
WHERE distinct_undistribured.user_id = test_cte_distributed.user_id)) exsist_in_distributed
|
|
ON distinct_undistribured.user_id = exsist_in_distributed.user_id
|
|
ORDER BY 2 DESC, 1 DESC;
|
|
user_id | user_id
|
|
---------------------------------------------------------------------
|
|
7 |
|
|
6 |
|
|
4 |
|
|
2 |
|
|
8 | 8
|
|
5 | 5
|
|
3 | 3
|
|
1 | 1
|
|
(8 rows)
|
|
|
|
WITH distinct_undistribured AS MATERIALIZED
|
|
(SELECT DISTINCT user_id
|
|
FROM test_cte)
|
|
SELECT *
|
|
FROM distinct_undistribured
|
|
LEFT JOIN
|
|
(SELECT DISTINCT user_id
|
|
FROM test_cte_distributed
|
|
WHERE NOT EXISTS
|
|
(SELECT NULL
|
|
FROM distinct_undistribured
|
|
WHERE distinct_undistribured.user_id = test_cte_distributed.user_id)) exsist_in_distributed ON distinct_undistribured.user_id = exsist_in_distributed.user_id
|
|
ORDER BY 1,2;
|
|
user_id | user_id
|
|
---------------------------------------------------------------------
|
|
1 |
|
|
2 |
|
|
3 |
|
|
4 |
|
|
5 |
|
|
6 |
|
|
7 |
|
|
8 |
|
|
(8 rows)
|
|
|
|
-- NOT EXISTS struct, with cte inlining disabled
|
|
WITH distinct_undistribured AS MATERIALIZED(
|
|
SELECT DISTINCT user_id
|
|
FROM test_cte
|
|
),
|
|
not_exsist_in_distributed AS MATERIALIZED (
|
|
SELECT DISTINCT user_id
|
|
FROM test_cte_distributed
|
|
WHERE NOT EXISTS(SELECT NULL
|
|
FROM distinct_undistribured
|
|
WHERE distinct_undistribured.user_id = test_cte_distributed.user_id)
|
|
)
|
|
SELECT
|
|
*
|
|
FROM
|
|
distinct_undistribured LEFT JOIN not_exsist_in_distributed
|
|
ON distinct_undistribured.user_id = not_exsist_in_distributed.user_id
|
|
ORDER BY 2 DESC, 1 DESC;
|
|
user_id | user_id
|
|
---------------------------------------------------------------------
|
|
8 |
|
|
7 |
|
|
6 |
|
|
5 |
|
|
4 |
|
|
3 |
|
|
2 |
|
|
1 |
|
|
(8 rows)
|
|
|
|
-- similar query, but this time the second
|
|
-- part of the query is not inside a CTE
|
|
WITH distinct_undistribured AS MATERIALIZED (
|
|
SELECT DISTINCT user_id
|
|
FROM test_cte
|
|
)
|
|
SELECT count(*)
|
|
FROM distinct_undistribured
|
|
LEFT JOIN
|
|
(SELECT *,
|
|
random()
|
|
FROM test_cte_distributed d1
|
|
WHERE NOT EXISTS
|
|
(SELECT NULL
|
|
FROM distinct_undistribured d2
|
|
WHERE d1.user_id = d2.user_id )) AS bar USING (user_id);
|
|
count
|
|
---------------------------------------------------------------------
|
|
8
|
|
(1 row)
|
|
|
|
-- some test with failures
|
|
WITH a AS MATERIALIZED (SELECT * FROM users_table LIMIT 10)
|
|
SELECT user_id/0 FROM users_table JOIN a USING (user_id);
|
|
ERROR: division by zero
|
|
CONTEXT: while executing command on localhost:xxxxx
|
|
DROP VIEW basic_view;
|
|
DROP VIEW cte_view;
|
|
DROP SCHEMA with_basics CASCADE;
|
|
NOTICE: drop cascades to 5 other objects
|
|
DETAIL: drop cascades to table users_table
|
|
drop cascades to table events_table
|
|
drop cascades to type xy
|
|
drop cascades to table test_cte
|
|
drop cascades to table test_cte_distributed
|