Часто при разработке отчетов в 1С программисты сталкиваются с ситуацией, когда в результат запроса попадают только те даты, в которых зафиксированы реальные обороты в регистре. Однако для анализа данных (например, в графиках продаж или планах) бывает необходимо вывести абсолютно все дни выбранного интервала, заполняя пропуски нулевыми значениями. Проблема заключается в том, что виртуальные таблицы 1С по умолчанию не генерируют строки для периодов без данных.
В этой статье мы подробно разберем, как заставить систему дополнять периоды, проанализируем синтаксис запроса и выясним, какие параметры программного обхода выборки критически важны для решения этой задачи.
Первым шагом к решению является правильная настройка блока итогов в тексте запроса. Обычная группировка не умеет «додумывать» недостающие даты. Для этого в языке запросов 1С предусмотрена специальная конструкция ПЕРИОДАМИ. Рассмотрим пример правильного написания запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПродажиОбороты.Номенклатура КАК Номенклатура,
| ПродажиОбороты.КоличествоОборот КАК Количество,
| ПродажиОбороты.СуммаОборот КАК Сумма,
| ПродажиОбороты.Период КАК Период
|ИЗ
| РегистрНакопления.Продажи.Обороты(&ДатаНачала, &ДатаОкончания, День, ) КАК ПродажиОбороты
|УПОРЯДОЧИТЬ ПО
| Период
|ИТОГИ
| СУММА(Количество),
| СУММА(Сумма)
|ПО
| ОБЩИЕ,
| Период ПЕРИОДАМИ(ДЕНЬ, &ДатаНачала, &ДатаОкончания),
| Номенклатура";
Запрос.УстановитьПараметр("ДатаНачала", НачалоДня(ДатаНачала));
Запрос.УстановитьПараметр("ДатаОкончания", КонецДня(ДатаОкончания));
Разберем, что происходит в этом коде. В блоке ИТОГИ мы указываем поле Период и добавляем ключевое слово ПЕРИОДАМИ. В скобках первым параметром указывается тип периода (ДЕНЬ, НЕДЕЛЯ, МЕСЯЦ), а затем границы интервала. Важно: если не указать параметры начала и окончания внутри скобок, система возьмет их из параметров виртуальной таблицы, но явное указание гарантирует корректность вывода.
Многие разработчики совершают ошибку: они пишут правильный запрос с конструкцией ПЕРИОДАМИ, но при выполнении кода в отчет все равно попадают только «заполненные» даты. Выясним причину: по умолчанию метод Выбрать() у результата запроса пропускает пустые записи итогов.
Чтобы система программно сгенерировала строки для отсутствующих дат, необходимо использовать специальный синтаксис метода Выбрать. Проанализируем правильный вариант обхода:
Результат = Запрос.Выполнить();
// Получаем общий итог
ВыборкаОбщийИтог = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
ВыборкаОбщийИтог.Следующий();
// Ключевой момент: обход по периодам с параметром "ВСЕ"
ВыборкаПериод = ВыборкаОбщийИтог.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Период", "ВСЕ");
Пока ВыборкаПериод.Следующий() Цикл
// Здесь будут все даты, даже те, по которым Количество и Сумма равны NULL или 0
ОбластьСтр.Параметры.Заполнить(ВыборкаПериод);
ТабДок.Вывести(ОбластьСтр);
КонецЦикла;
Обратите внимание на строку ВыборкаОбщийИтог.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Период", "ВСЕ"). Третий параметр "ВСЕ" является строковым значением. Именно он заставляет 1С «развернуть» временную шкалу и создать фиктивные записи для тех дней, по которым в базе данных нет записей. Если вы просто напишете Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам), пустые даты будут проигнорированы.
Рассмотрим ситуацию, когда нам нужно вывести данные в разрезе Номенклатура — Дата. Порядок следования полей в блоке ПО раздела ИТОГИ имеет критическое значение для логики дополнения:
Период стоит первым (как в примере выше), система сначала выведет все даты интервала, а внутри каждой даты — только те товары, которые продавались в этот день.Номенклатура стоит первой (ПО Номенклатура, Период ПЕРИОДАМИ...), то при обходе по каждой номенклатуре система выведет полный календарь дат. Это идеально подходит для формирования кросс-таблиц, где по строкам идут товары, а по колонкам — все дни месяца.Проанализируем пример кода для случая «Все даты для каждого товара»:
// В запросе: ИТОГИ ПО Номенклатура, Период ПЕРИОДАМИ...
ВыборкаНоменклатура = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока ВыборкаНоменклатура.Следующий() Цикл
// Для каждой номенклатуры принудительно выводим все даты
ВыборкаПериод = ВыборкаНоменклатура.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Период", "ВСЕ");
Пока ВыборкаПериод.Следующий() Цикл
// Обработка данных...
КонецЦикла;
КонецЦикла;
Иногда использование механизма ИТОГИ неудобно, например, если вам нужно выгрузить результат в ТаблицаЗначений. Стоит помнить, что метод Выгрузить() полностью игнорирует настройки дополнения периодов — он работает только с «физическими» данными, которые вернула СУБД. В таком случае мы рекомендуем использовать метод левого соединения с заранее подготовленным календарем.
Рассмотрим алгоритм действий:
ЕСТЬNULL(ПолеРесурса, 0), чтобы вместо пустых значений в «недостающих» датах отображались нули.Посмотрим на пример такого запроса:
// Допустим, ВТ_Календарь уже создана и содержит поле "Дата"
Запрос.Текст =
"ВЫБРАТЬ
| Календарь.Дата КАК Период,
| ЕСТЬNULL(Продажи.КоличествоОборот, 0) КАК Количество
|ИЗ
| ВТ_Календарь КАК Календарь
|ЛЕВОЕ СОЕДИНЕНИЕ
| РегистрНакопления.Продажи.Обороты(&Начало, &Конец, День) КАК Продажи
|ПО Календарь.Дата = Продажи.Период";
Этот метод более трудоемок в написании кода, но он дает стабильный результат при выгрузке в таблицы или при использовании в сложных построителях отчетов.
При работе с дополнением периодов следует учитывать несколько технических особенностей:
ПЕРИОДАМИ, все поля, кроме самого периода, будут иметь значение NULL. Будьте осторожны при обращении к реквизитам через точку (например, Выборка.Номенклатура.Артикул), это может вызвать ошибку.ИТОГИ ПЕРИОДАМИ в самом запросе не нужно. В компоновщике есть штатный механизм: на закладке «Настройки» для группировки по периоду выберите пункт «Дополнение периодов» и укажите тип (день, месяц) и границы."ВСЕ") выполняется на уровне сервера приложений 1С, а не на SQL-сервере. Если период очень большой, а группировок много, это может замедлить формирование отчета.Таким образом, мы выяснили, что для решения задачи достаточно скомбинировать инструкцию ИТОГИ ПЕРИОДАМИ в тексте запроса и параметр "ВСЕ" в методе Выбрать(). Это стандартный и наиболее эффективный путь для разработки классических отчетов в среде 1С:Предприятие.