-- Complex nested CTEs
CREATE SCHEMA with_nested;
SET search_path tO with_nested, public;
CREATE TABLE with_nested.local_users (user_id int, event_type int);
INSERT INTO local_users VALUES (0, 0), (1, 4), (1, 7), (2, 1), (3, 3), (5, 4), (6, 2), (10, 7);
-- Can refer to outer CTE because it is recursively planned first
WITH cte_1 AS (
  SELECT DISTINCT user_id FROM users_table
),
cte_2 AS (
  WITH cte_1_1 AS (
     SELECT * FROM cte_1 WHERE user_id > 1
  )
  SELECT * FROM cte_1_1 WHERE user_id < 3
)
SELECT user_id FROM cte_2 LIMIT 1;
 user_id
---------------------------------------------------------------------
       2
(1 row)

-- Nested CTEs
WITH users_events AS (
  WITH users_events_2 AS (
    SELECT
        users_table.user_id as user_id,
        events_table.event_type as event_type
    FROM
        users_table,
        events_table
    WHERE
        users_table.user_id = events_table.user_id
    GROUP BY
        users_table.user_id,
        events_table.event_type
  )
  SELECT
      u_events.user_id, events_table.event_type
  FROM
    users_events_2 as u_events,
    events_table
  WHERE
    u_events.user_id = events_table.user_id
  )
SELECT
  *
FROM
  users_events
ORDER BY
  1, 2
LIMIT 20;
 user_id | event_type
---------------------------------------------------------------------
       1 |          0
       1 |          0
       1 |          0
       1 |          0
       1 |          0
       1 |          0
       1 |          0
       1 |          0
       1 |          0
       1 |          0
       1 |          0
       1 |          0
       1 |          1
       1 |          1
       1 |          1
       1 |          1
       1 |          1
       1 |          1
       1 |          1
       1 |          1
(20 rows)

-- Nested CTEs
WITH users_events AS (
  WITH users_events AS (
    WITH users_events AS (
      WITH users_events AS (
        WITH users_events AS (
          WITH users_events AS (
            WITH users_events AS (
              SELECT
                  users_table.user_id as user_id,
                  events_table.event_type as event_type
              FROM
                  users_table,
                  events_table
              WHERE
                  users_table.user_id = events_table.user_id
              GROUP BY
                  users_table.user_id,
                  events_table.event_type
            )
            SELECT
                uid, event_type, value_2, value_3
            FROM
               (
                (
                  SELECT
                    user_id as uid
                  FROM
                    users_events
                ) users
                join
                  events_table
                on
                  users.uid = events_table.event_type
                ) a
            )
          SELECT
            *
          FROM
            users_events
          ORDER BY
            1, 3, 2, 4
          LIMIT 100
        )
        SELECT
          *
        FROM
          users_events
        LIMIT 90
      )
      SELECT
        *
      FROM
        users_events
      LIMIT 50
    )
    SELECT
      uid, event_type, value_2, sum(value_3) as sum_3
    FROM
      users_events
    GROUP BY
      1, 2, 3
    LIMIT 40
  )
  SELECT
    uid, event_type, sum(value_2) as sum_2, sum(sum_3) as sum_3
  FROM
    users_events
  GROUP BY
    1, 2
  LIMIT 30
)
SELECT
  uid, avg(event_type), sum(sum_2), sum(sum_3)
FROM
  users_events
GROUP BY
  1;
 uid |          avg           | sum | sum
---------------------------------------------------------------------
   1 | 1.00000000000000000000 |   3 |  72
(1 row)

-- Nested CTEs
WITH users_events AS (
  -- router select query
  WITH users_events_1 AS (
    SELECT
      *
    FROM
      users_table
    WHERE
      user_id = 1
  ),
  -- real-time select query
  users_events_2_3 AS (
    SELECT
      *
    FROM
      users_table
    WHERE
      user_id = 2
      OR
      user_id = 3
  ),
  -- router select query
  -- sub CTE is a real-time executor query but the top level is router select
  users_events_4 AS (
    WITH users_events_4_5 AS (
    SELECT
      *
    FROM
      users_table
    WHERE
      user_id = 4
      OR
      user_id = 5
    )
    SELECT
        *
    FROM
        users_events_4_5
    WHERE
        user_id = 4
  ),
  -- merge all the results from CTEs
  merged_users AS (
      SELECT
        *
      FROM
        users_events_1
    UNION
      SELECT
        *
      FROM
        users_events_2_3
    UNION
      SELECT
        *
      FROM
        users_events_4
  )
  SELECT
    *
  FROM
    merged_users
)
SELECT
  *
FROM
  users_events
ORDER BY
  1, 2, 3, 4, 5, 6
LIMIT
  20;
 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 |
       1 | Thu Nov 23 17:23:03.441394 2017 |       5 |       4 |       3 |
       1 | Thu Nov 23 17:30:34.635085 2017 |       3 |       4 |       4 |
       1 |                                 |         |         |         |
       2 | Wed Nov 22 18:19:49.944985 2017 |       3 |       5 |       1 |
       2 | Thu Nov 23 00:19:14.138058 2017 |       3 |       4 |       0 |
       2 | Thu Nov 23 01:04:26.198826 2017 |       4 |       3 |       4 |
       2 | Thu Nov 23 01:14:27.658529 2017 |       4 |       4 |       4 |
       2 | Thu Nov 23 03:27:50.327051 2017 |       2 |       2 |       0 |
       2 | Thu Nov 23 06:01:08.148777 2017 |       2 |       4 |       2 |
       2 | Thu Nov 23 06:23:53.572592 2017 |       4 |       4 |       5 |
       2 | Thu Nov 23 06:50:30.797805 2017 |       1 |       1 |       1 |
       2 | Thu Nov 23 06:56:38.46819 2017  |       0 |       1 |       3 |
       2 | Thu Nov 23 08:22:22.169158 2017 |       4 |       2 |       5 |
       2 | Thu Nov 23 08:49:47.029236 2017 |       4 |       2 |       4 |
       2 | Thu Nov 23 09:54:28.13665 2017  |       0 |       3 |       4 |
(20 rows)

-- Nested CTEs - joined with local table. Not supported yet.
WITH users_events AS (
  -- router select query
  WITH users_events_1 AS (
    SELECT
      *
    FROM
      users_table
    WHERE
      user_id = 1
  ),
  -- real-time select query
  users_events_2_3 AS (
    SELECT
      *
    FROM
      users_table
    WHERE
      user_id = 2
      OR
      user_id = 3
  ),
  -- router select query
  -- sub CTE is a real-time executor query but the top level is router select
  users_events_4 AS (
    WITH users_events_4_5 AS (
    SELECT
      *
    FROM
      users_table
    WHERE
      user_id = 4
      OR
      user_id = 5
    )
    SELECT
        *
    FROM
        users_events_4_5
    WHERE
        user_id = 4
  )
  -- merge all the results from CTEs
      SELECT
        *
      FROM
        users_events_1
  UNION
      SELECT
        *
      FROM
        users_events_2_3
  UNION
      SELECT
        *
     FROM
       users_events_4
)
SELECT
  *
FROM
  users_events
ORDER BY
  1, 2, 3, 4, 5, 6
LIMIT
  20;
 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 |
       1 | Thu Nov 23 17:23:03.441394 2017 |       5 |       4 |       3 |
       1 | Thu Nov 23 17:30:34.635085 2017 |       3 |       4 |       4 |
       1 |                                 |         |         |         |
       2 | Wed Nov 22 18:19:49.944985 2017 |       3 |       5 |       1 |
       2 | Thu Nov 23 00:19:14.138058 2017 |       3 |       4 |       0 |
       2 | Thu Nov 23 01:04:26.198826 2017 |       4 |       3 |       4 |
       2 | Thu Nov 23 01:14:27.658529 2017 |       4 |       4 |       4 |
       2 | Thu Nov 23 03:27:50.327051 2017 |       2 |       2 |       0 |
       2 | Thu Nov 23 06:01:08.148777 2017 |       2 |       4 |       2 |
       2 | Thu Nov 23 06:23:53.572592 2017 |       4 |       4 |       5 |
       2 | Thu Nov 23 06:50:30.797805 2017 |       1 |       1 |       1 |
       2 | Thu Nov 23 06:56:38.46819 2017  |       0 |       1 |       3 |
       2 | Thu Nov 23 08:22:22.169158 2017 |       4 |       2 |       5 |
       2 | Thu Nov 23 08:49:47.029236 2017 |       4 |       2 |       4 |
       2 | Thu Nov 23 09:54:28.13665 2017  |       0 |       3 |       4 |
(20 rows)

-- access to uncle, use window function, apply aggregates, use group by, LIMIT/OFFSET
WITH cte1 AS (
  WITH cte1_1 AS (
    WITH cte1_1_1 AS (
      SELECT user_id, time, value_2 FROM users_table
    ),
    cte1_1_2 AS (
      SELECT
        user_id, count
      FROM (
              SELECT
                      user_id,
                      count(value_2) OVER (PARTITION BY user_id)
              FROM
                      users_table
              GROUP BY 1, users_table.value_2
      )aa
      GROUP BY
        1,2
      ORDER BY
        1,2
      LIMIT
        4
      OFFSET
        2
    )
    SELECT cte1_1_1.user_id, cte1_1_1.time, cte1_1_2.count FROM cte1_1_1 join cte1_1_2 on cte1_1_1.user_id=cte1_1_2.user_id
  ),
  cte1_2 AS (
    WITH cte1_2_1 AS (
      SELECT
        user_id, time, avg(value_1)::real as value_1, min(value_2) as value_2
      FROM
        users_table
      GROUP BY
        1, 2
    ),
    cte1_2_2 AS (
      SELECT cte1_2_1.user_id, cte1_1.time, cte1_2_1.value_1, cte1_1.count FROM cte1_2_1 join cte1_1 on cte1_2_1.time=cte1_1.time and cte1_2_1.user_id=cte1_1.user_id
    )
    SELECT * FROM cte1_2_2
  )
  SELECT * FROM cte1_2
),
cte2 AS (
  WITH cte2_1 AS (
    WITH cte2_1_1 AS (
      SELECT * FROM cte1
    )
    SELECT user_id, time, value_1, min(count) FROM cte2_1_1 GROUP BY 1, 2, 3 ORDER BY 1,2,3
  )
  SELECT * FROM cte2_1 ORDER BY 1,2,3,4 LIMIT 3 OFFSET 2
)
SELECT * FROM cte2;
 user_id |              time               | value_1 | min
---------------------------------------------------------------------
       3 | Wed Nov 22 23:24:32.080584 2017 |       3 |   5
       3 | Thu Nov 23 00:15:45.610845 2017 |       1 |   5
       3 | Thu Nov 23 03:23:24.702501 2017 |       1 |   5
(3 rows)

DROP SCHEMA with_nested CASCADE;
NOTICE:  drop cascades to table local_users
