Как правильно обработать результат запроса с вложенной табличной частью в 1С?

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

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

Проанализируем, почему это происходит и какими способами можно правильно обработать вложенные данные в коде 1С.

Выясним причину: какой тип данных возвращает вложенный запрос

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    Организации.Наименование КАК Наименование,
    |    Организации.ИНН КАК ИНН,
    |    Организации.КонтактнаяИнформация.(
    |        Тип КАК Тип,
    |        Представление КАК Представление
    |    ) КАК КонтактнаяИнформация
    |ИЗ
    |    Справочник.Организации КАК Организации";

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

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

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

Способ 1. Вложенная выборка (рекомендуемый вариант)

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

Разберем реализацию этого способа на примере:


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

Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    
    НаименованиеОрг = ВыборкаДетальныеЗаписи.Наименование;
    ИННОрг          = ВыборкаДетальныеЗаписи.ИНН;
    
    // Получаем выборку по вложенной табличной части
    ВыборкаКИ = ВыборкаДетальныеЗаписи.КонтактнаяИнформация.Выбрать();
    
    Пока ВыборкаКИ.Следующий() Цикл
        ТипКИ           = ВыборкаКИ.Тип;
        ПредставлениеКИ = ВыборкаКИ.Представление;
        
        // Обработка данных контактной информации
    КонецЦикла;

КонецЦикла;

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

Способ 2. Выгрузка в таблицу значений

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

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


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

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

КонецЦикла;

Ограничения использования вложенных таблиц в запросах

При выборе способа построения запроса важно учитывать следующие особенности платформы 1С:

  1. Несовместимость с группировками: В запросах, использующих выборку вложенных табличных частей ТЧ.(...), нельзя применять конструкции СГРУППИРОВАТЬ ПО, ИТОГИ и РАЗЛИЧНЫЕ.
  2. Временные таблицы: Вложенную таблицу невозможно поместить во временную таблицу с помощью инструкции ПОМЕСТИТЬ.
  3. Производительность: При выборке огромных массивов данных обработка вложенных выборок может вызывать дополнительные затраты ресурсов сервера.

Альтернативные архитектурные решения

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

1. Запрос непосредственно к табличной части (получение «плоской» таблицы)

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


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

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

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

2. Использование связи с регистром сведений (для типовых конфигураций БСП)

В современных типовых конфигурациях (1С:ERP, 1С:Управление торговлей, 1С:Бухгалтерия предприятия 3.0 и др.) контактная информация хранятся не в табличных частях справочника, а в регистре сведений РегистрСведений.КонтактнаяИнформация. В таких системах следует выполнять ЛЕВОЕ СОЕДИНЕНИЕ справочника с этим регистром сведений по ссылке объекта или использовать функции программного модуля БСП УправлениеКонтактнойИнформацией.

← На главную