Как исправить ошибку «Поле агрегатного объекта не обнаружено» при выгрузке запроса в Таблицу Значений в 1С 7.7?

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

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

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

Выясняем причину ошибки на примере исходного кода

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


// Создание объекта Запрос и определение текста запроса
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = "
|Период с ДатаНач по ДатаКон;
|ОбрабатыватьДокументы все;
|Обрабатывать НеПомеченныеНаУдаление;
|Без итогов;
|Док   = Документ.ПоступлениеТоваров.ТекущийДокумент;
|Фирма = Документ.ПоступлениеТоваров.фармФирма;
|Контрагент = Документ.ПоступлениеТоваров.Контрагент;
|// |Группировка Док упорядочить по Док.ДатаДок без групп все ВошедшиеВЗапрос;
|Условие (Фирма в Организация );";

Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
    ТЗ = СоздатьОбъект("ТаблицаЗначений");
    Запрос.Выгрузить(ТЗ); 
    ТЗ.ВыбратьСтроки();
    Пока ТЗ.ПолучитьСтроку() = 1 Цикл
        Сообщить(ТЗ.Док.ДатаНомерСчетаФактуры); // Ошибка: Поле агрегатного объекта не обнаружено Док
    КонецЦикла;
КонецЕсли;

Почему этот код вызывает ошибку на строке с методом Сообщить? Обратим внимание на то, что строка описания группировки |Группировка Док... закомментирована. Это критически важно.

В платформе 1С 7.7 переменные, объявленные в запросе (такие как Док, Фирма, Контрагент), делятся на три категории:

  1. Группировки — переменные, по которым строятся разрезы многомерного отчета.
  2. Функции — агрегатные вычисления (Сумма, Среднее, Счетчик и т.д.).
  3. Дополнительные (внутренние) переменные — переменные запроса, которые не участвуют в группировках или функциях, но используются для наложения условий или получения детальной информации.

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

Разбираем по шагам синтаксис метода Выгрузить()

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

Выгрузить(ТаблЗнач, Флаг, Итоги)

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

1. Параметр «ТаблЗнач»

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

2. Параметр «Флаг» (управление составом колонок)

Этот параметр определяет, какие переменные запроса превратятся в колонки таблицы значений. Он может принимать числовые или строковые значения:

3. Параметр «Итоги» (управление строками итоговых записей)

Этот параметр отвечает за перенос строк промежуточных и общих итогов группировок в результирующую таблицу значений. По умолчанию он равен 1 (выводить итоги).

Если оставить этот параметр по умолчанию, первой строкой в вашей таблице всегда будет идти строка общего итога. В этой строке колонка группировки Док будет иметь пустое значение. При обходе такой таблицы в цикле первая же попытка обратиться к реквизитам пустого значения (например, ТЗ.Док.ДатаНомерСчетаФактуры) вызовет падение программы. Чтобы получить «чистую» таблицу, содержащую только детальные строки, всегда принудительно устанавливайте этот параметр в значение 0.

Решение 1. Использование технической группировки (Рекомендуемое)

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

Посмотрим на пример правильного кода с использованием группировки:


Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = "
|Период с ДатаНач по ДатаКон;
|ОбрабатыватьДокументы все;
|Обрабатывать НеПомеченныеНаУдаление;
|Без итогов;
|Док   = Документ.ПоступлениеТоваров.ТекущийДокумент;
|Фирма = Документ.ПоступлениеТоваров.фармФирма;
|Контрагент = Документ.ПоступлениеТоваров.Контрагент;
|Группировка Док без групп; // Добавляем группировку без иерархии
|Условие (Фирма в Организация);";

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

Решение 2. Выгрузка без группировок с использованием флагов

Если по каким-то причинам вы категорически не хотите использовать группировки в тексте запроса, вам необходимо явно указать платформе, что дополнительные переменные должны попасть в результирующую ТЗ. Для этого мы применим флаг 1 в методе выгрузки.

Разберем пример реализации этого подхода по шагам:


Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = "
|Период с ДатаНач по ДатаКон;
|ОбрабатыватьДокументы все;
|Обрабатывать НеПомеченныеНаУдаление;
|Без итогов;
|Док   = Документ.ПоступлениеТоваров.ТекущийДокумент;
|Фирма = Документ.ПоступлениеТоваров.фармФирма;
|Контрагент = Документ.ПоступлениеТоваров.Контрагент;
|Условие (Фирма в Организация);";

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

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

Взаимодействие директивы «Без итогов» и параметров выгрузки

В текстах запросов часто используется директива |Без итогов;. Она сообщает движку СУБД, что не нужно тратить ресурсы на предварительный расчет агрегатных данных по группировкам на сервере БД. Это существенно ускоряет выполнение запроса.

Но обратите внимание: если в запросе прописано Без итогов;, а при выгрузке в ТЗ вы забыли указать третий параметр равным 0 (то есть оставили его по умолчанию равным 1), платформа все равно попытается вставить пустые строки итогов в начало вашей ТЗ. Это не только приведет к нерациональному расходу памяти, но и заставит вас писать дополнительные проверки на пустоту значений при обходе таблицы. Всегда пишите связку Запрос.Выгрузить(ТЗ, Флаг, 0), если в запросе присутствует оператор Без итогов;.

Важное предупреждение: Ограничение памяти в 1С 7.7

Платформа 1С:Предприятие 7.7 является классическим 32-разрядным приложением. Это накладывает жесткое ограничение на объем оперативной памяти, выделяемой под один рабочий сеанс (не более 2 ГБ физического адресного пространства).

Объект ТаблицаЗначений полностью располагается в оперативной памяти компьютера. Если ваш запрос обрабатывает сотни тысяч строк детальных данных (например, спецификации накладных за несколько лет), выгрузка через Запрос.Выгрузить(ТЗ) может мгновенно исчерпать доступную память. Вы получите критический сбой системы с ошибкой «Недостаточно памяти» (Out of memory) и аварийное закрытие программы.

Для предотвращения подобных ситуаций придерживайтесь следующих правил разработки:

← На главную