Как создать N таблиц значений в цикле в 1С 7.7?

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

При разработке сложных отчетов, пакетных обработок и выгрузок данных в платформе 1С 7.7 часто возникает необходимость сформировать динамическое количество коллекций данных — например, отдельную таблицу значений для каждого документа или контрагента. Начинающие разработчики нередко пытаются динамически объявлять переменные или использовать конструкции вида Перем ТЗ[N], что приводит к синтаксическим ошибкам или непредсказуемому поведению программы. Разберем по шагам, какие существуют ограничения платформы и какими способами можно правильно создавать и адресовать N таблиц значений.

Ограничения платформы 1С 7.7 при работе с динамическими коллекциями

Прежде чем перейти к практическим решениям, проанализируем базовые особенности встроенного языка 1С:Предприятия 7.7:

  1. Статическая размерность массивов: размерность массива в операторе Перем должна быть строго константным числовым литералом (например, Перем МассивТЗ[100]). Задать размер массива через переменную (например, Перем МассивТЗ[Количество]) на этапе компиляции модуля невозможно.
  2. Отсутствие динамического именования переменных: в коде нельзя на лету генерировать имена локальных переменных вроде ТЗ_1, ТЗ_2. Для адресации по именам или индексам необходимо использовать специализированные контейнеры.
  3. Ссылочная модель данных: при простом присваивании одной переменной другой копируется ссылка на объект в оперативной памяти, а не его содержимое. Для создания независимой копии требуется явное создание объекта и выгрузка структуры.

Вариант 1. Использование массива с фиксированной размерностью

Если максимальное количество таблиц заранее известно или ограничено разумным числом, простейшим решением является объявление массива. Рассмотрим пример:


Процедура СформироватьМассивТЗ()
    Перем МассивТЗ[100];
    
    Для к = 1 По 10 Цикл
        МассивТЗ[к] = СоздатьОбъект("ТаблицаЗначений");
        МассивТЗ[к].НоваяКолонка("Идентификатор");
        МассивТЗ[к].НоваяКолонка("Сумма");
        
        МассивТЗ[к].НоваяСтрока();
        МассивТЗ[к].Идентификатор = к;
        МассивТЗ[к].Сумма = к * 100;
    КонецЦикла;
    
    // Обращение к конкретной таблице по индексу:
    МассивТЗ[1].ВыбратьСтроку(,"Первая таблица");
КонецПроцедуры

Важный момент: объявление Перем задает жесткий верхний предел. Если в процессе работы понадобится 101-я таблица, программа выдаст ошибку выхода за границы массива.

Вариант 2. Хранение таблиц значений в колонке родительской ТЗ

Наиболее гибкий и распространенный способ — создание структуры «таблица в таблице». В качестве контейнера используется одна главная таблица значений, у которой одна из колонок имеет тип ТаблицаЗначений. Рассмотрим подробнее код создания и наполнения такой структуры на примере выборки документов:


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

Вариант 3. Использование объекта СписокЗначений для именования таблиц

Когда требуется обращаться к созданным таблицам значений не по числовому индексу, а по текстовому строковому представлению (имени), удобно использовать СписокЗначений. Метод ДобавитьЗначение() принимает сам объект и строковое представление:


Процедура СоздатьТаблицыВХранилище()
    ХранилищеТЗ = СоздатьОбъект("СписокЗначений");
    КоличествоТЗ = 5;
    
    Для ы = 1 По КоличествоТЗ Цикл
        ИмяТЗ = "Таблица_" + СокрЛП(ы);
        
        ВременнаяТЗ = СоздатьОбъект("ТаблицаЗначений");
        ВременнаяТЗ.НоваяКолонка("Параметр");
        ВременнаяТЗ.НоваяСтрока();
        ВременнаяТЗ.Параметр = "Значение " + СокрЛП(ы);
        
        ХранилищеТЗ.ДобавитьЗначение(ВременнаяТЗ, ИмяТЗ);
    КонецЦикла;
    
    // Получение таблицы по индексу из списка:
    Для Позиция = 1 По ХранилищеТЗ.РазмерСписка() Цикл
        ИмяТаблицы = "";
        ТекущаяТЗ = ХранилищеТЗ.ПолучитьЗначение(Позиция, ИмяТаблицы);
        Сообщить("Обработка объекта с именем: " + ИмяТаблицы);
    КонецЦикла;
КонецПроцедуры

Вариант 4. Использование COM-объекта Scripting.Dictionary для поиска по ключу

Если критически важно обращаться к N таблицам напрямую по произвольному текстовому ключу без перебора списка, наилучшим решением выступает системный ассоциативный массив Scripting.Dictionary:


Процедура СоздатьСловарьТаблиц()
    СловарьТЗ = СоздатьОбъект("Scripting.Dictionary");
    
    Для Индекс = 1 По 10 Цикл
        Ключ = "ТЗ_Склад_" + СокрЛП(Индекс);
        
        НоваяТЗ = СоздатьОбъект("ТаблицаЗначений");
        НоваяТЗ.НоваяКолонка("Номенклатура");
        НоваяТЗ.НоваяКолонка("Остаток");
        
        СловарьТЗ.Add(Ключ, НоваяТЗ);
    КонецЦикла;
    
    // Прямой доступ по имени без циклов:
    Если СловарьТЗ.Exists("ТЗ_Склад_3") = 1 Тогда
        НужнаяТЗ = СловарьТЗ.Item("ТЗ_Склад_3");
        НужнаяТЗ.НоваяСтрока();
    КонецЕсли;
КонецПроцедуры

Критическая ошибка платформы: почему метод Заполнить() приводит к аварийному завершению

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


// ОШИБОЧНЫЙ КОД — ПРИВОДИТ К ПАДЕНИЮ ПРОГРАММЫ (CRASH 1cv7s.exe)
ТЗ = СоздатьОбъект("ТаблицаЗначений");
ТЗ.НоваяКолонка("КолонкаТЗ", "ТаблицаЗначений");
ТЗ.КоличествоСтрок(10);
ТЗ.Заполнить(СоздатьОбъект("ТаблицаЗначений"), 1, 10, "КолонкаТЗ");

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

Правильный подход: создание нового экземпляра таблицы значений через СоздатьОбъект("ТаблицаЗначений") должно выполняться строго внутри цикла на каждой итерации для каждой отдельной строки.

Управление памятью при работе с вложенными таблицами

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

← На главную