Рекурсивный запрос посложнее

Разберем пример, когда в нерекурсивной части несколько строк. Построим наборы чисел от 100 до 103 и от 200 до 201:

WITH RECURSIVE lv_initial AS (
    SELECT 100 AS start_number,
           4 AS count_iterations
     UNION ALL
    SELECT 200 AS start_number,
           2 AS count_iterations
), 
lv_numbers (start_number, count_iterations, current_iteration, result_number) AS (
    SELECT start_number,
           count_iterations,
           1 AS current_iteration,
           start_number AS result_number
      FROM lv_initial
     UNION ALL
    SELECT p.start_number,
           p.count_iterations,
           p.current_iteration + 1,
           p.result_number + 1
      FROM lv_numbers p
     WHERE p.current_iteration < p.count_iterations
)
SELECT n.start_number,
       n.result_number
  FROM lv_numbers n
 ORDER BY n.start_number,
          n.result_number
# start_number result_number
1 100 100
2 100 101
3 100 102
4 100 103
5 200 200
6 200 201

Обрати внимание, ключевое слово RECURSIVE стоит не перед рекурсивным подзапросом, а сразу после WITH.

Как выполняется запрос

Шаг 1. Выполняется нерекурсивная часть подзапроса.

Таблица lv_initial:

# start_number count_iterations
1 100 4
2 200 2

Результат нерекурсивной части:

# start_number count_iterations current_iteration result_number
1 100 4 1 100
2 200 2 1 200

Временная таблица:

# start_number count_iterations current_iteration result_number
1 100 4 1 100
2 200 2 1 200

Шаг 2. Рекурсивная часть выполняется 1-й раз

Начальная временная таблица

# start_number count_iterations current_iteration result_number
1 100 4 1 100
2 200 2 1 200

Результат подзапроса

    SELECT p.start_number,
           p.count_iterations,
           p.current_iteration + 1,
           p.result_number + 1
      FROM lv_numbers p
     WHERE p.current_iteration < p.count_iterations
# start_number count_iterations current_iteration result_number
1 100 4 2 101
2 200 2 2 201

Общий результат запроса

# start_number count_iterations current_iteration result_number
1 100 4 1 100
2 200 2 1 200
3 100 4 2 101
4 200 2 2 201

Временная таблица

# start_number count_iterations current_iteration result_number
1 100 4 2 101
2 200 2 2 201

Шаг 3. Рекурсивная часть выполняется 2-й раз

Начальная временная таблица

# start_number count_iterations current_iteration result_number
1 100 4 2 101
2 200 2 2 201

Результат подзапроса

    SELECT p.start_number,
           p.count_iterations,
           p.current_iteration + 1,
           p.result_number + 1
      FROM lv_numbers p
     WHERE p.current_iteration < p.count_iterations
# start_number count_iterations current_iteration result_number
1 100 4 3 102

Общий результат запроса

# start_number count_iterations current_iteration result_number
1 100 4 1 100
2 200 2 1 200
3 100 4 2 101
4 200 2 2 201
5 100 4 3 102

Временная таблица

# start_number count_iterations current_iteration result_number
1 100 4 3 102

Шаг 4. Рекурсивная часть выполняется 3-й раз

Начальная временная таблица

# start_number count_iterations current_iteration result_number
1 100 4 3 102

Результат подзапроса

    SELECT p.start_number,
           p.count_iterations,
           p.current_iteration + 1,
           p.result_number + 1
      FROM lv_numbers p
     WHERE p.current_iteration < p.count_iterations
# start_number count_iterations current_iteration result_number
1 100 4 4 103

Общий результат запроса

# start_number count_iterations current_iteration result_number
1 100 4 1 100
2 200 2 1 200
3 100 4 2 101
4 200 2 2 201
5 100 4 3 102
6 100 4 4 103

Временная таблица

# start_number count_iterations current_iteration result_number
1 100 4 4 103

Шаг 5. Рекурсивная часть выполняется 4-й раз

Начальная временная таблица

# start_number count_iterations current_iteration result_number
1 100 4 4 103

Результат подзапроса

    SELECT p.start_number,
           p.count_iterations,
           p.current_iteration + 1,
           p.result_number + 1
      FROM lv_numbers p
     WHERE p.current_iteration < p.count_iterations
0 строк

Общий результат запроса

# start_number count_iterations current_iteration result_number
1 100 4 1 100
2 200 2 1 200
3 100 4 2 101
4 200 2 2 201
5 100 4 3 102
6 100 4 4 103

Временная таблица пуста. На этом рекурсивная часть запроса завершает выполнение.

Шаг 6. Выполняется основной запрос

SELECT n.start_number,
       n.result_number
  FROM lv_numbers n
 ORDER BY n.start_number,
          n.result_number
# start_number result_number
1 100 100
2 100 101
3 100 102
4 100 103
5 200 200
6 200 201

10.4 Простейший рекурсивный запрос

10.6 Строим иерархию объектов