Почему в запросе 1С 7.7 группировка по месяцу не выводится для групп номенклатуры и как это исправить?

Программист 1С v7.7 Управленческий учет Торговля и дистрибуция
← На главную

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

Причина поведения платформы 1С 7.7

Рассмотрим стандартный текст запроса, где первой указана группировка по справочнику, а второй — по периоду:


|Товар = Регистр.ОстаткиТоваров.Товар;
|ОстатокТовара = Регистр.ОстаткиТоваров.ОстатокТовара;
|ПродСумма = Регистр.ОстаткиТоваров.ПродСумма;
|Функция ОстатокТовараРасход = Расход(ОстатокТовара);
|Функция ПродСуммаРасход = Расход(ПродСумма);
|Группировка Товар;
|Группировка Месяц Все ВошедшиеВЗапрос;

Выясним причину, по которой для групп номенклатуры временные срезы остаются пустыми. Архитектура встроенного генератора запросов 1С 7.7 при использовании иерархической группировки (по умолчанию для справочников) рассчитывает для строк-групп (Запрос.ЭтоГруппа() = 1) исключительно общий агрегированный итог за весь интервал отчета. Платформа не формирует вложенную выборку второго уровня (Запрос.Группировка(2)) для папок справочника, поэтому обход выборки месяцев для узлов дерева не возвращает строк.

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

Способ 1. Агрегация и расчет итогов по иерархии через Таблицу Значений

Если требуется использовать исключительно штатные средства платформы, лучшим решением является получение плоских данных без иерархии с последующим расчетом итогов по дереву справочника в объекте ТаблицаЗначений.

Разберем алгоритм по шагам:

  1. Выполняем запрос с модификатором Без Групп, получая обороты только по элементам и периодам.
  2. Выгружаем результат в ТаблицаЗначений.
  3. Проходим по таблице и для каждой строки рекурсивно поднимаемся по цепочке родителей через свойство Родитель, суммируя показатели по соответствующему месяцу в итоговую структуру.
  4. Выводим подготовленную таблицу в отчет с соблюдением уровней вложенности.

Посмотрим на пример реализации запроса и первичной обработки:


ТекстЗапроса = "
|Период С ВыбНачПериода По ВыбКонПериода;
|Товар = Регистр.ОстаткиТоваров.Товар;
|ОстатокТовара = Регистр.ОстаткиТоваров.ОстатокТовара;
|Функция КоличествоРасход = Расход(ОстатокТовара);
|Группировка Товар Без Групп;
|Группировка Месяц Все;
|";

Запрос = СоздатьОбъект("Запрос");
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    ТЗ = СоздатьОбъект("ТаблицаЗначений");
    Запрос.Выгрузить(ТЗ, 1, 0);
    // Дополнительная обработка: сворачивание и суммирование родительских узлов
КонецЕсли;

Способ 2. Изменение порядка группировок и поворот данных

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


|Группировка Месяц Все;
|Группировка Товар;

При таком порядке сначала выбирается месяц, а внутри него — вся иерархия номенклатуры с рассчитанными суммами по группам именно за этот месяц. Для вывода отчета в привычном виде (где номенклатура расположена по вертикали, а месяцы — по горизонтали или внутри строк) результат запроса перегружается в промежуточную таблицу значений и транспонируется («переворачивается») перед печатью.

Способ 3. Построение кросс-таблицы с помощью Индексированной Таблицы (1С++)

При наличии внешней компоненты 1С++ задачу можно решить быстро и эффективно с помощью объекта ИндексированнаяТаблица. Мы можем развернуть периоды в отдельные динамические колонки и затем применить иерархическую группировку с автоматическим расчетом итогов по папкам.

Рассмотрим подробный пример кода:


ТекстЗапроса = "
|Период С ВыбНачПериода По ВыбКонПериода;
|Товар = Регистр.ОстаткиТоваров.Товар;
|Количество = Регистр.ОстаткиТоваров.ОстатокТовара;
|Функция КоличествоРасход = Расход(Количество);
|Функция КоличествоПриход = Приход(Количество);
|Группировка Товар Без Групп;
|Группировка Месяц Все;
|";

Запрос = СоздатьОбъект("Запрос");
Запрос.Выполнить(ТекстЗапроса);

итз = СоздатьОбъект("ИндексированнаяТаблица");
итз.ЗагрузитьЗапрос(Запрос);

СписокРесурсов = СоздатьОбъект("СписокЗначений");
СписокРесурсов.ДобавитьЗначение("КоличествоРасход");
СписокРесурсов.ДобавитьЗначение("КоличествоПриход");

СписокМесяцев = СоздатьОбъект("СписокЗначений");
СтрокиСумм = "";
итз.ДобавитьИндекс("Месяц", "*Месяц");
итз.Выгрузить(СписокМесяцев, "Месяц", "Месяц", 1);

Для ии1 = 1 По СписокРесурсов.РазмерСписка() Цикл
    ИмяРесурса = СписокРесурсов.ПолучитьЗначение(ии1);
    Для ии2 = 1 По СписокМесяцев.РазмерСписка() Цикл
        Месяц = СписокМесяцев.ПолучитьЗначение(ии2);
        ИмяКолонки = ИмяРесурса + Месяц;
        итз.НоваяКолонка(ИмяКолонки);
        СтрокиСумм = СтрокиСумм + ?(СтрокиСумм = "", "", ",") + ИмяКолонки;
        итз.УстановитьФильтр(Месяц, Месяц, "Месяц");
        итз.ЗаполнитьКолонку("Месяц", ИмяКолонки, итз, "Месяц", ИмяРесурса);
    КонецЦикла;
КонецЦикла;

// Группировка с иерархией по товару и автоматическим расчетом сумм по колонкам месяцев
итз.Группировать("Товар:Товар&", СтрокиСумм, 1);

Символ & в выражении Товар:Товар& указывает объекту ИндексированнаяТаблица на необходимость построения иерархического дерева групп и элементов с автоматическим расчетом сумм по всем указанным колонкам месяцев.

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

← На главную