Справочник по функциям

WITH

Конструкция SQL

Задаёт именованный подзапрос (общее табличное выражение, CTE), к которому основной запрос обращается как к таблице.

MySQL 8.1
WITH [RECURSIVE] name_cte [(column[, ...])] AS (subquery) main_query
  • [ ]необязательная часть
  • ...можно повторить
RECURSIVE
Разрешает табличному выражению ссылаться на само себя
Ключевое словоНеобязательный
name_cte
Имя табличного выражения
Имя
column
Имена столбцов табличного выражения, по умолчанию берутся из subquery
ИмяНеобязательный
subquery
Подзапрос, результат которого доступен по имени name_cte
Подзапрос
main_query
Основной запрос, который обращается к name_cte как к таблице
Подзапрос

Возвращаемое значение

Временная именованная выборка, доступная только в этом запросе

Примеры

Число рейсов каждой компании

MySQL 8.1
WITH company_trips AS (
	SELECT company,
		COUNT(*) AS trips
	FROM Trip
	GROUP BY company
)
SELECT Company.name,
	company_trips.trips
FROM company_trips
	JOIN Company ON Company.id = company_trips.company
ORDER BY company_trips.trips DESC;
nametrips
British_AW10
Don_avia6
Aeroflot2
Dale_avia2
air_France2

Числа от 1 до 5 через RECURSIVE

MySQL 8.1
WITH RECURSIVE numbers (n) AS (
	SELECT 1
	UNION ALL
	SELECT n + 1
	FROM numbers
	WHERE n < 5
)
SELECT n
FROM numbers;
n
1
2
3
4
5

Строка растёт в рекурсии

MySQL 8.1
WITH RECURSIVE stars (n, line) AS (
	SELECT 1,
		CAST('*' AS CHAR(10))
	UNION ALL
	SELECT n + 1,
		CONCAT(line, '*')
	FROM stars
	WHERE n < 5
)
SELECT n,
	line
FROM stars;
nline
1*
2**
3***
4****
5*****

Подробности

После одного WITH можно перечислить через запятую несколько табличных выражений, и каждое может ссылаться на предыдущие.

Рекурсивное выражение состоит из начального запроса и рекурсивной части, соединённых через UNION ALL или UNION (он ещё убирает повторы), и должно содержать условие остановки. По умолчанию рекурсивная часть выполняется не больше 1000 раз (переменная cte_max_recursion_depth), дальше запрос завершается ошибкой.

Типы столбцов задаёт начальный запрос. Если рекурсивная часть удлиняет строку, начальное значение нужно расширить заранее: CAST('*' AS CHAR(10)), иначе будет ошибка «Data too long».

Смотрите также

Где изучить