0Pricing
SQL Interview Prep · Урок

Генерация последовательностей чисел и дат

Используйте рекурсию для создания последовательностей при заполнении пропусков и построении календарей.

«Генерация последовательностей чисел и дат» — бесплатный урок SQL Interview Prep на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения SQL Interview Prep, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс SQL Interview Prep содержит 4 уроков всего.

Рекурсия без иерархии

Рекурсивные CTE нужны не только для деревьев. Второе важное применение — создание последовательностей: ряда чисел или каждой даты в заданном диапазоне. На собеседованиях об этом спрашивают, когда в задаче требуется заполнение пропусков — создание строк, которых нет ни в одной таблице.

Классическая формулировка: «Покажите продажи за каждый день месяца, включая дни без продаж». Нельзя показать отсутствующий день, пока сначала не создать все дни.

Простой ряд чисел

Начальная часть задаёт первое число; рекурсивная часть на каждой итерации увеличивает его на единицу; условие WHERE в рекурсивной части останавливает процесс. Так создаются числа от 1 до 10.

WITH RECURSIVE nums AS (
    SELECT 1 AS n
    UNION ALL
    SELECT n + 1 FROM nums WHERE n < 10
)
SELECT n FROM nums;

Условие завершения

В отличие от организационной структуры, у ряда чисел нет естественного конечного элемента, на котором можно остановиться: увеличивать число можно бесконечно. Поэтому в рекурсивную часть необходимо добавить явное условие остановки: WHERE n < 10.

Когда n достигает 10, условие WHERE следующей итерации отфильтровывает единственную строку-кандидат, рекурсивная часть не возвращает ничего, и рекурсия останавливается. Забытое ограничение — причина номер один неконтролируемой рекурсии на собеседованиях.

Параметризация диапазона

Сделайте последовательность гибкой, задавая границу значением или переменной. Здесь создаётся ряд от 1 до N, где N передаётся извне. По той же схеме можно создавать последовательности с началом от 0 или с заданным шагом — достаточно изменить начальное значение и приращение.

WITH RECURSIVE nums AS (
    SELECT 1 AS n
    UNION ALL
    SELECT n + 2 FROM nums WHERE n + 2 <= 99
)
SELECT n FROM nums;  -- odd numbers 1,3,5,...,99

Создание ряда дат

Замените арифметику целых чисел арифметикой дат — и получите календарь. Начальная часть задаёт начальную дату; рекурсивная часть добавляет один день, пока не выйдет за конечную дату.

Синтаксис добавления дня зависит от диалекта — здесь используется форма в стиле Postgres с интервалом.

WITH RECURSIVE cal AS (
    SELECT DATE '2024-01-01' AS d
    UNION ALL
    SELECT d + INTERVAL '1 day'
    FROM cal
    WHERE d < DATE '2024-01-31'
)
SELECT d FROM cal;

Заполнение пропусков с помощью LEFT JOIN

Теперь объедините календарь с реальными данными. Создайте каждую дату, а затем выполните LEFT JOIN с таблицей продаж, чтобы отсутствующие дни появились со значением NULL, которое с помощью COALESCE преобразуется в 0.

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

WITH RECURSIVE cal AS (
    SELECT DATE '2024-01-01' AS d
    UNION ALL
    SELECT d + INTERVAL '1 day' FROM cal
    WHERE d < DATE '2024-01-07'
)
SELECT cal.d, COALESCE(SUM(s.amount), 0) AS total
FROM cal
LEFT JOIN sales s ON s.sale_date = cal.d
GROUP BY cal.d
ORDER BY cal.d;

Месячные и недельные основы

Измените приращение, чтобы строить календари с более крупным шагом. Добавьте INTERVAL '1 month' для помесячной основы или INTERVAL '7 day' для понедельной. Это полезно, когда на собеседовании требуется помесячный отчёт, включающий пустые месяцы.

WITH RECURSIVE months AS (
    SELECT DATE '2024-01-01' AS m
    UNION ALL
    SELECT m + INTERVAL '1 month' FROM months
    WHERE m < DATE '2024-12-01'
)
SELECT m FROM months;

Различия диалектов в арифметике дат

Арифметика дат — наименее переносимая часть таких запросов. Знайте варианты:

  • Postgres: d + INTERVAL '1 day'.
  • MySQL: DATE_ADD(d, INTERVAL 1 DAY).
  • SQL Server: DATEADD(DAY, 1, d).
  • SQLite: date(d, '+1 day').

Сильный ответ с пониманием диалектов — отметить, что структура рекурсии одинакова и меняется только функция работы с датами.

Рекурсия и generate_series

В Postgres есть встроенная функция generate_series(), которая создаёт числа или даты без рекурсии, причём быстрее и понятнее:

SELECT generate_series(DATE '2024-01-01', DATE '2024-01-31', INTERVAL '1 day');

Если база данных на собеседовании поддерживает эту функцию, используйте её. Однако во многих системах (в MySQL и SQL Server до недавних версий) её нет — именно в таких случаях рекурсивный CTE становится переносимым запасным вариантом.

Следите за пределом рекурсии

Создание большого ряда может достичь ограничения рекурсии системы. В SQL Server по умолчанию задано MAXRECURSION 100, поэтому календарь на 365 дней завершится ошибкой, если не добавить OPTION (MAXRECURSION 0) для снятия ограничения.

В Postgres фиксированного ограничения нет, но неконтролируемая последовательность с неправильным условием может выполняться, пока не закончится память. Перед увеличением масштаба всегда проверяйте правильность условия завершения.

-- SQL Server: lift the 100-row recursion cap
-- ...recursive CTE here...
SELECT * FROM cal
OPTION (MAXRECURSION 0);

Объединение ряда декартовым произведением

Созданный ряд часто является лишь составной частью решения. Получив CTE с числами, объедините его с помощью CROSS JOIN, чтобы расширить или размножить строки — например, повторить каждую строку заказа по количеству или развернуть диапазон дат отдельно для каждого клиента.

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

WITH RECURSIVE nums AS (
    SELECT 1 AS n
    UNION ALL
    SELECT n + 1 FROM nums WHERE n < 10
)
SELECT o.order_id, nums.n AS unit
FROM orders o
JOIN nums ON nums.n <= o.quantity;

Быстрая проверка

Почему условие остановки критично для ряда чисел или дат?

Итоги

Рекурсия может создавать строки, которых нет ни в одной таблице:

  • Задайте первое значение в начальной части, а приращение — в рекурсивной части.
  • Всегда добавляйте явное условие завершения — у последовательностей нет естественного конца.
  • Постройте основу из дат или чисел, затем присоедините факты с помощью LEFT JOIN и используйте COALESCE для заполнения пропусков.
  • Используйте generate_series, если он доступен, и учитывайте MAXRECURSION в SQL Server.

Далее: методы безопасности, которые не дают рекурсии выйти из-под контроля.

Часто задаваемые вопросы

Урок «Генерация последовательностей чисел и дат» бесплатный?

Да — полный текст урока «Генерация последовательностей чисел и дат» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс SQL Interview Prep, подпишись на CoddyKit PRO. Курс SQL Interview Prep содержит 4 уроков всего.

Чему я научусь в уроке «Генерация последовательностей чисел и дат»?

Используйте рекурсию для создания последовательностей при заполнении пропусков и построении календарей. Ты практикуешь SQL Interview Prep с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать SQL Interview Prep?

Предыдущий опыт не требуется. SQL Interview Prep на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Генерация последовательностей чисел и дат»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке SQL Interview Prep?

Да. Каждый урок SQL Interview Prep включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Якорная и рекурсивная части
  2. Обход организационной структуры
  3. Генерация последовательностей чисел и дат
  4. Предотвращение бесконечной рекурсии
← Назад к SQL Interview Prep