Открыть сервис

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

Рекурсивный запрос — это в информатике и теории баз данных запрос, который ссылается сам на себя, то есть результат выполнения запроса на одном шаге используется в качестве входных данных для следующего шага. В контексте систем управления базами данных (СУБД) рекурсивные запросы обычно реализуются с помощью общего табличного выражения (Common Table Expression, CTE) и оператора WITH RECURSIVE, что позволяет обрабатывать иерархические или древовидные структуры данных (например, организационные иерархии, категории товаров, генеалогические деревья, графы связей) без необходимости написания сложных процедурных циклов на внешнем языке программирования.

История и развитие

Концепция рекурсии в запросах возникла из потребности эффективно работать с иерархическими данными в реляционных базах данных, которые изначально не были оптимизированы для таких структур. В 1980-х годах, с ростом популярности реляционных СУБД, разработчики столкнулись с проблемой: для обхода дерева (например, подчинённых в организации) приходилось писать хранимые процедуры или использовать несколько последовательных запросов, что было громоздко и неэффективно.

Первые реализации рекурсивных запросов появились в коммерческих СУБД в начале 1990-х годов. Например, IBM DB2 ввела поддержку рекурсивных CTE в версии 2.0 (1993 год). Стандарт SQL:1999 (ISO/IEC 9075-2:1999) официально включил рекурсивные запросы в спецификацию языка SQL, определив синтаксис WITH RECURSIVE. Однако многие крупные СУБД (включая MySQL) внедрили эту возможность лишь в 2010-х годах. MySQL добавил поддержку рекурсивных CTE в версии 8.0 (2018 год), а PostgreSQL — значительно раньше, начиная с версии 8.4 (2009 год). В настоящее время рекурсивные запросы поддерживаются всеми основными реляционными СУБД: Oracle Database (с версии 11gR2 через CONNECT BY или WITH RECURSIVE), Microsoft SQL Server (с версии 2005), SQLite (с версии 3.8.3, 2014 год) и другими.

Принцип работы

Рекурсивный запрос в SQL состоит из двух частей, объединённых оператором UNION ALL или UNION:

  1. Базовый (якорный) член (anchor member) — начальный запрос, который выбирает корневые элементы иерархии или начальные данные. Он выполняется один раз и формирует первую итерацию рекурсии.
  2. Рекурсивный член (recursive member) — запрос, который ссылается на сам CTE. Он выполняется многократно, каждый раз используя результат предыдущей итерации в качестве входных данных. Рекурсия продолжается до тех пор, пока рекурсивный член не вернёт пустой набор строк (условие завершения).

Синтаксис общего вида:

``sql WITH RECURSIVE cte_name (column_list) AS ( -- Базовый член SELECT ... UNION ALL -- Рекурсивный член SELECT ... FROM cte_name WHERE ... ) SELECT * FROM cte_name; ``

Пример: Поиск всех подчинённых сотрудника в иерархии «руководитель — подчинённый».

Таблица employees:

idnamemanager_id
1ИвановNULL
2Петров1
3Сидоров2
4Кузнецов1

Запрос для поиска всех подчинённых Иванова (id=1):

``sql WITH RECURSIVE subordinates AS ( SELECT id, name, manager_id FROM employees WHERE id = 1 -- Базовый член: сам Иванов UNION ALL SELECT e.id, e.name, e.manager_id FROM employees e INNER JOIN subordinates s ON e.manager_id = s.id -- Рекурсивный член: подчинённые ) SELECT * FROM subordinates; ``

Результат: Иванов, Петров, Сидоров, Кузнецов.

Виды рекурсивных запросов

Рекурсивные запросы классифицируются по типу обрабатываемых данных и способу завершения рекурсии:

Применение

Рекурсивные запросы широко используются в различных областях:

Ограничения и особенности

Критика и альтернативы

Рекурсивные запросы критикуются за сложность отладки и низкую производительность на глубоких иерархиях. Альтернативными подходами являются:

Интересные факты

Источники

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →