Как правильно реализовать разворот таблицы по периодам в 1С 7.7 и избежать критических ошибок

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

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

Анализ проблем и ошибок самописного алгоритма разворота

Рассмотрим типовой вариант, когда результат запроса выгружается в ТаблицаЗначений, после чего в цикле формируется составной строковый ключ и выполняется поиск строк через НайтиЗначение(). Проанализируем критические уязвимости такого подхода:

  1. Идентификация объектов по их строковому представлению. Конкатенация ссылочных объектов неявно приводит их к строке (по наименованию). Если в базе присутствуют разные элементы справочника с совпадающими наименованиями либо подчиненные справочники с одинаковыми именами у разных владельцев (например, единицы измерения «шт.»), данные разных позиций ошибочно объединятся в одну строку. Для получения строго уникального строкового идентификатора объекта в 1С 7.7 следует применять функцию ЗначениеВСтрокуВнутр().
  2. Сломанная логика составного ключа во внутреннем цикле. Если проверка наличия строки и добавление новых строк выполняются внутри цикла по колонкам измерений, а не после сборки полного составного ключа строки, таблица начинает дублировать строки и искажать показатели.
  3. Катастрофическое падение производительности (сложность O(N²)). Метод НайтиЗначение() в объекте ТаблицаЗначений выполняет линейный перебор строк. При росте объема выборки до тысяч строк алгоритм с ручным поиском приводит к полной заморозке сеанса 1С.
  4. Ошибочное определение измерений по типу данных. Исключение колонок по условию равенства типа «Число» отсекает числовые измерения (например, год, номер квартала или числовой реквизит справочника).
  5. Безымянные динамические колонки. Добавление колонок методом НоваяКолонка(,"Число") без строкового идентификатора заставляет обращаться к колонкам по их номерам со сдвигом, что делает алгоритм хрупким при малейшем изменении структуры колонок.

Способ 1. Штатный разворот через метод Свернуть()

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

  1. Получаем уникальный список периодов (например, через временную таблицу или выгрузку запроса).
  2. Добавляем в исходную таблицу значений колонки для каждого периода с фиксированными именами (например, Период_1, Период_2 или М_2026_01).
  3. В одном быстром цикле переносим сумму из исходной колонки в колонку, соответствующую периоду текущей строки.
  4. Вызываем встроенный метод Свернуть(), передавая список измерений и список колонок-периодов.

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


// Подготовим список измерений и список суммируемых колонок-периодов
СписГруппировок = "Покупатель,Номенклатура";
СписПериодов = "";

// Создаем колонки периодов в ТЗ
ТЗПериоды.ВыбратьСтроки();
Пока ТЗПериоды.ПолучитьСтроку() = 1 Цикл
    ИмяКол = "П_" + СтрЗаменить(Строка(ТЗПериоды.Месяц), ".", "_");
    ТЗ.НоваяКолонка(ИмяКол, "Число", 15, 2);
    СписПериодов = СписПериодов + ?(СписПериодов = "", "", ",") + ИмяКол;
КонецЦикла;

// Переносим показатели в соответствующие колонки периодов
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл
    ИмяКол = "П_" + СтрЗаменить(Строка(ТЗ.Месяц), ".", "_");
    ТЗ.УстановитьЗначение(ТЗ.НомерСтроки, ИмяКол, ТЗ.ПродСтоимостьСумма);
КонецЦикла;

// Однократное платформенное сворачивание всей таблицы
ТЗ.Свернуть(СписГруппировок, СписПериодов);

Способ 2. Прямой вывод без промежуточных таблиц через объект Запрос

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

Разберем последовательность действий:

  1. В тексте запроса для периодической группировки указываем флаг Все ВошедшиеВЗапрос.
  2. Обходим строки вертикальных группировок стандартным методом Группировка().
  3. Для вывода горизонтальных колонок выполняем позиционирование методом Получить() по текущему периоду и выводим секции методом ПрисоединитьСекцию().

Рассмотрим пример запроса и обхода выборки:


ТекстЗапроса = 
"//{{ЗАПРОС(Сформировать)
|Период с (НачДата) по (КонДата);
|Покупатель = Регистр.Продажи.Покупатель;
|Номенклатура = Регистр.Продажи.Номенклатура;
|ПродСтоимость = Регистр.Продажи.ПродСтоимость;
|Функция СуммаПрод = Сумма(ПродСтоимость);
|Группировка Покупатель без групп;
|Группировка Номенклатура без групп;
|Группировка Месяц Все ВошедшиеВЗапрос;
|";

Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    Таб.ВывестиСекцию("Шапка");
    
    // Формируем горизонтальную шапку периодов
    Пока Запрос.Группировка("Месяц") = 1 Цикл
        Таб.ПрисоединитьСекцию("ШапкаПериод");
    КонецЦикла;
    
    // Обход строк аналитики
    Пока Запрос.Группировка("Покупатель") = 1 Цикл
        Пока Запрос.Группировка("Номенклатура") = 1 Цикл
            Таб.ВывестиСекцию("СтрокаАналитика");
            
            // Вывод колонок периодов прямым позиционированием
            Запрос.Группировка("Месяц", 1);
            Пока Запрос.Группировка("Месяц") = 1 Цикл
                // Значение ячейки доступно напрямую из запроса
                Таб.ПрисоединитьСекцию("СтрокаПериод");
            КонецЦикла;
        КонецЦикла;
    КонецЦикла;
КонецЕсли;

Способ 3. Внешние компоненты и быстрые индексированные таблицы

Когда требуется выполнять сложную обработку больших массивов данных вне запроса (например, при чтении информации из внешних файлов или Excel), стандартная ТаблицаЗначений платформы 1С 7.7 упирается в ограничения по скорости поиска. В таких задачах применяются специализированные классы и объекты:

  1. Индексированная Таблица Значений (ИТЗ): компонент, добавляющий B-Tree индексы к колонкам ТаблицаЗначений. Поиск по составным ключам выполняется мгновенно (сложность O(log N) вместо O(N)).
  2. Прямые SQL-запросы: при работе с SQL-версией 1С 7.7 формирование кросс-таблиц переносится на сторону СУБД с помощью условных операторов CASE WHEN или агрегатных функций, что исключает передачу лишних данных по сети и разгружает клиентскую станцию.
← На главную