Как вывести все даты периода в запросе 1С, даже если по ним не было движений

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

Часто при разработке отчетов в 1С программисты сталкиваются с ситуацией, когда в результат запроса попадают только те даты, в которых зафиксированы реальные обороты в регистре. Однако для анализа данных (например, в графиках продаж или планах) бывает необходимо вывести абсолютно все дни выбранного интервала, заполняя пропуски нулевыми значениями. Проблема заключается в том, что виртуальные таблицы 1С по умолчанию не генерируют строки для периодов без данных.

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

Использование конструкции ПЕРИОДАМИ в тексте запроса

Первым шагом к решению является правильная настройка блока итогов в тексте запроса. Обычная группировка не умеет «додумывать» недостающие даты. Для этого в языке запросов 1С предусмотрена специальная конструкция ПЕРИОДАМИ. Рассмотрим пример правильного написания запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   ПродажиОбороты.Номенклатура КАК Номенклатура,
    |   ПродажиОбороты.КоличествоОборот КАК Количество,
    |   ПродажиОбороты.СуммаОборот КАК Сумма,
    |   ПродажиОбороты.Период КАК Период
    |ИЗ
    |   РегистрНакопления.Продажи.Обороты(&ДатаНачала, &ДатаОкончания, День, ) КАК ПродажиОбороты
    |УПОРЯДОЧИТЬ ПО
    |   Период
    |ИТОГИ
    |   СУММА(Количество),
    |   СУММА(Сумма)
    |ПО
    |   ОБЩИЕ,
    |   Период ПЕРИОДАМИ(ДЕНЬ, &ДатаНачала, &ДатаОкончания),
    |   Номенклатура";

Запрос.УстановитьПараметр("ДатаНачала", НачалоДня(ДатаНачала));
Запрос.УстановитьПараметр("ДатаОкончания", КонецДня(ДатаОкончания));

Разберем, что происходит в этом коде. В блоке ИТОГИ мы указываем поле Период и добавляем ключевое слово ПЕРИОДАМИ. В скобках первым параметром указывается тип периода (ДЕНЬ, НЕДЕЛЯ, МЕСЯЦ), а затем границы интервала. Важно: если не указать параметры начала и окончания внутри скобок, система возьмет их из параметров виртуальной таблицы, но явное указание гарантирует корректность вывода.

Секрет программного обхода: параметр ВСЕ

Многие разработчики совершают ошибку: они пишут правильный запрос с конструкцией ПЕРИОДАМИ, но при выполнении кода в отчет все равно попадают только «заполненные» даты. Выясним причину: по умолчанию метод Выбрать() у результата запроса пропускает пустые записи итогов.

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


Результат = Запрос.Выполнить();

// Получаем общий итог
ВыборкаОбщийИтог = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
ВыборкаОбщийИтог.Следующий();

// Ключевой момент: обход по периодам с параметром "ВСЕ"
ВыборкаПериод = ВыборкаОбщийИтог.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Период", "ВСЕ");

Пока ВыборкаПериод.Следующий() Цикл
    // Здесь будут все даты, даже те, по которым Количество и Сумма равны NULL или 0
    ОбластьСтр.Параметры.Заполнить(ВыборкаПериод);
    ТабДок.Вывести(ОбластьСтр);
КонецЦикла;

Обратите внимание на строку ВыборкаОбщийИтог.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Период", "ВСЕ"). Третий параметр "ВСЕ" является строковым значением. Именно он заставляет 1С «развернуть» временную шкалу и создать фиктивные записи для тех дней, по которым в базе данных нет записей. Если вы просто напишете Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам), пустые даты будут проигнорированы.

Влияние иерархии группировок на результат

Рассмотрим ситуацию, когда нам нужно вывести данные в разрезе Номенклатура — Дата. Порядок следования полей в блоке ПО раздела ИТОГИ имеет критическое значение для логики дополнения:

  1. Если Период стоит первым (как в примере выше), система сначала выведет все даты интервала, а внутри каждой даты — только те товары, которые продавались в этот день.
  2. Если Номенклатура стоит первой (ПО Номенклатура, Период ПЕРИОДАМИ...), то при обходе по каждой номенклатуре система выведет полный календарь дат. Это идеально подходит для формирования кросс-таблиц, где по строкам идут товары, а по колонкам — все дни месяца.

Проанализируем пример кода для случая «Все даты для каждого товара»:


// В запросе: ИТОГИ ПО Номенклатура, Период ПЕРИОДАМИ...
ВыборкаНоменклатура = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Пока ВыборкаНоменклатура.Следующий() Цикл
    // Для каждой номенклатуры принудительно выводим все даты
    ВыборкаПериод = ВыборкаНоменклатура.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Период", "ВСЕ");
    
    Пока ВыборкаПериод.Следующий() Цикл
        // Обработка данных...
    КонецЦикла;
КонецЦикла;

Альтернативный метод: Левое соединение с таблицей дат

Иногда использование механизма ИТОГИ неудобно, например, если вам нужно выгрузить результат в ТаблицаЗначений. Стоит помнить, что метод Выгрузить() полностью игнорирует настройки дополнения периодов — он работает только с «физическими» данными, которые вернула СУБД. В таком случае мы рекомендуем использовать метод левого соединения с заранее подготовленным календарем.

Рассмотрим алгоритм действий:

  1. Создаем временную таблицу, в которую помещаем все даты нужного периода. Даты можно получить из производственного календаря или сформировать программно в цикле и передать в запрос как массив/таблицу значений.
  2. Выполняем ЛЕВОЕ СОЕДИНЕНИЕ этой таблицы дат с данными из регистра накопления.
  3. Используем функцию ЕСТЬNULL(ПолеРесурса, 0), чтобы вместо пустых значений в «недостающих» датах отображались нули.

Посмотрим на пример такого запроса:


// Допустим, ВТ_Календарь уже создана и содержит поле "Дата"
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Календарь.Дата КАК Период,
    |   ЕСТЬNULL(Продажи.КоличествоОборот, 0) КАК Количество
    |ИЗ
    |   ВТ_Календарь КАК Календарь
    |ЛЕВОЕ СОЕДИНЕНИЕ
    |   РегистрНакопления.Продажи.Обороты(&Начало, &Конец, День) КАК Продажи
    |ПО Календарь.Дата = Продажи.Период";

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

Важные нюансы и ограничения

При работе с дополнением периодов следует учитывать несколько технических особенностей:

Таким образом, мы выяснили, что для решения задачи достаточно скомбинировать инструкцию ИТОГИ ПЕРИОДАМИ в тексте запроса и параметр "ВСЕ" в методе Выбрать(). Это стандартный и наиболее эффективный путь для разработки классических отчетов в среде 1С:Предприятие.

← На главную