Как исправить ошибку «Итератор для значения не определен» при обходе результата запроса в 1С

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

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

Причины возникновения ошибки

В платформе 1С цикл Для Каждого ... Из ... Цикл предназначен исключительно для объектов-коллекций, поддерживающих интерфейс перечисления (например, массив, структура, соответствие, таблица значений, дерево значений, коллекция колонок или строк). Рассмотрим типичные ошибочные конструкции, приводящие к сбою:

  1. Попытка итерации по объекту Запрос или ВыборкаИзРезультатаЗапроса: Конструкция вида Для Каждого Стр Из Запрос Цикл вызывает исключение, поскольку сам объект Запрос не содержит в себе данных и не является коллекцией.
  2. Использование несуществующих свойств: Обращение к Запрос.Ссылка или попытка обратиться по индексу через квадратные скобки к объекту выборки или запроса Запрос["ИмяПоля"] недопустимы.
  3. Некорректное получение выборки: Вызов цепочки методов вида Запрос.Выполнить().Выбрать().Следующий() возвращает булево значение (Истина/Ложь), а не саму выборку или строку данных.

Способ 1. Последовательный обход через объект ВыборкаИзРезультатаЗапроса

Если требуется последовательно прочитать данные запроса с минимальным расходом оперативной памяти, используем объект ВыборкаИзРезультатаЗапроса. Обход выборки выполняется с помощью цикла Пока ... Цикл и вызова метода Следующий().

Разберем пример корректного кода для обхода данных выборки:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    Сотрудники.Ссылка КАК Сотрудник,
    |    Сотрудники.Код КАК Код,
    |    Сотрудники.ТекущееПодразделение КАК Подразделение
    |ИЗ
    |    Справочник.Сотрудники КАК Сотрудники";

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

Пока Выборка.Следующий() Цикл
    // Обращение к полям осуществляется через точку по имени поля
    ЗначениеСотрудник = Выборка.Сотрудник;
    ЗначениеКод = Выборка.Код;
КонецЦикла;

Обратите внимание: при работе с выборкой обращение к полям осуществляется через точку по имени колонки, заданной в тексте запроса (например, Выборка.Сотрудник).

Способ 2. Выгрузка в Таблицу Значений для динамического обращения к колонкам

Когда стоит задача динамически перебирать имена колонок (например, через строковые переменные СтрокаДанных[ИмяКолонки]) или обходить строки с помощью конструкции Для Каждого, результат запроса необходимо предварительно выгрузить в Таблицу Значений.

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


РезультатЗапроса = Запрос.Выполнить();
ТаблицаДанных = РезультатЗапроса.Выгрузить();

// 1. Формируем заголовки колонок в файле Excel
КолонкаЛиста = 1;
Для Каждого Колонка Из ТаблицаДанных.Колонки Цикл
    Лист.Cells(1, КолонкаЛиста).Value = Колонка.Имя;
    КолонкаЛиста = КолонкаЛиста + 1;
КонецЦикла;

// 2. Построчно выгружаем данные
СтрокаЛиста = 2;
Для Каждого СтрокаТаблицы Из ТаблицаДанных Цикл
    КолонкаЛиста = 1;
    Для Каждого Колонка Из ТаблицаДанных.Колонки Цикл
        // Доступ к значению по имени колонки через квадратные скобки
        ЗначениеЯчейки = СтрокаТаблицы[Колонка.Имя];
        
        Если ТипЗнч(ЗначениеЯчейки) = Тип("Число") Тогда
            Лист.Cells(СтрокаЛиста, КолонкаЛиста).NumberFormat = "0,00";
            Лист.Cells(СтрокаЛиста, КолонкаЛиста).Value = Формат(ЗначениеЯчейки, "ЧГ=0");
        Иначе
            Лист.Cells(СтрокаЛиста, КолонкаЛиста).NumberFormat = "@";
            Лист.Cells(СтрокаЛиста, КолонкаЛиста).Value = Строка(ЗначениеЯчейки);
        КонецЕсли;
        
        КолонкаЛиста = КолонкаЛиста + 1;
    КонецЦикла;
    СтрокаЛиста = СтрокаЛиста + 1;
КонецЦикла;

Оптимизация экспорта: Альтернатива COM-объектам

Поячеечная запись данных через COM-объект Excel (Лист.Cells(Row, Col).Value = ...) работает крайне медленно на больших объемах информации и зависит от установленного пакета MS Office на рабочем месте. Разберем более быстрый и универсальный способ формирования Excel-файла с помощью встроенного Табличного Документа.

Рассмотрим пример формирования файла через табличный документ:


ТабДок = Новый ТабличныйДокумент;

// Заполняем табличный документ данными из выборки или таблицы
// ... (вывод областей макета)

// Сохраняем результат в формате XLSX напрямую средствами платформы
ТабДок.Записать(ПолноеИмяФайла, ТипФайлаТабличногоДокумента.XLSX);

Если же бизнес-логика требует использования COM-соединения, всегда очищайте память и закрывайте приложение после завершения работы:


Книга.SaveAs(ПолноеИмяФайла);
ПриложениеExcel.Quit();

// Освобождаем COM-объекты для исключения зависания процесса EXCEL.EXE
Лист = Неопределено;
Книга = Неопределено;
ПриложениеExcel = Неопределено;
← На главную