При написании запросов к справочникам или документам часто возникает необходимость одновременно с реквизитами объекта получить данные из его табличной части. В языке запросов 1С для этого используется специальный синтаксис обращения к табличной части через скобки вида ИмяТабличнойЧасти.(Поле1, Поле2). Однако при обработке результатов такого запроса разработчики часто сталкиваются с ошибкой: обращение к полученному полю вложенной таблицы как к обычной коллекции вызывает сбой.
Проанализируем, почему это происходит и какими способами можно правильно обработать вложенные данные в коде 1С.
Разберем типичный пример. Допустим, мы выполняем следующий запрос для получения списка организаций и их контактной информации из табличной части:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Организации.Наименование КАК Наименование,
| Организации.ИНН КАК ИНН,
| Организации.КонтактнаяИнформация.(
| Тип КАК Тип,
| Представление КАК Представление
| ) КАК КонтактнаяИнформация
|ИЗ
| Справочник.Организации КАК Организации";
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Когда мы обходим основную выборку с помощью цикла Пока ВыборкаДетальныеЗаписи.Следующий() Цикл, значение в поле ВыборкаДетальныеЗаписи.КонтактнаяИнформация не является ни таблицей значений, ни массивом. Если заглянуть в отладчик, мы увидим, что тип данного поля — РезультатЗапроса.
Поскольку это объект типа РезультатЗапроса, к нему нельзя напрямую применить цикл Для Каждого. Чтобы прочитать из него данные, необходимо воспользоваться стандартными методами объекта РезультатЗапроса: методом Выбрать() или методом Выгрузить().
Рассмотри наиболее оптимальный с точки зрения использования памяти способ. Для обработки строк табличной части внутри основного цикла обхода мы вызываем метод Выбрать() у поля вложенного результата запроса. Это создает вложенную выборку, которую мы обходим отдельным циклом Пока ... Следующий().
Разберем реализацию этого способа на примере:
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
НаименованиеОрг = ВыборкаДетальныеЗаписи.Наименование;
ИННОрг = ВыборкаДетальныеЗаписи.ИНН;
// Получаем выборку по вложенной табличной части
ВыборкаКИ = ВыборкаДетальныеЗаписи.КонтактнаяИнформация.Выбрать();
Пока ВыборкаКИ.Следующий() Цикл
ТипКИ = ВыборкаКИ.Тип;
ПредставлениеКИ = ВыборкаКИ.Представление;
// Обработка данных контактной информации
КонецЦикла;
КонецЦикла;
Этот подход является наиболее эффективным, так как платформа не расходует лишнюю память на создание промежуточных таблиц значений в оперативной памяти.
Посмотрим на второй вариант обработки. Если полученные строки табличной части требуется передавать далее в другие процедуры, сортировать или дополнительно фильтровать, вложенный результат можно выгрузить в таблицу значений с помощью метода Выгрузить().
Пример обработки с выгрузкой в таблицу значений:
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
НаименованиеОрг = ВыборкаДетальныеЗаписи.Наименование;
ИННОрг = ВыборкаДетальныеЗаписи.ИНН;
// Выгружаем вложенный результат запроса в Таблицу Значений
ТаблицаКИ = ВыборкаДетальныеЗаписи.КонтактнаяИнформация.Выгрузить();
Для Каждого СтрокаКИ Из ТаблицаКИ Цикл
ТипКИ = СтрокаКИ.Тип;
ПредставлениеКИ = СтрокаКИ.Представление;
КонецЦикла;
КонецЦикла;
При выборе способа построения запроса важно учитывать следующие особенности платформы 1С:
ТЧ.(...), нельзя применять конструкции СГРУППИРОВАТЬ ПО, ИТОГИ и РАЗЛИЧНЫЕ.ПОМЕСТИТЬ.Проанализируем альтернативные варианты решения задачи, которые часто применяются на практике.
1. Запрос непосредственно к табличной части (получение «плоской» таблицы)
Вместо использования вложенных таблиц можно написать запрос напрямую к табличной части справочника. В этом случае мы получаем обычный плоский результат запроса, который обрабатывается одним простым циклом:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОрганизацииКИ.Ссылка.Наименование КАК Наименование,
| ОрганизацииКИ.Ссылка.ИНН КАК ИНН,
| ОрганизацииКИ.Тип КАК Тип,
| ОрганизацииКИ.Представление КАК Представление
|ИЗ
| Справочник.Организации.КонтактнаяИнформация КАК ОрганизацииКИ";
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Доступ к полям организации и контактной информации в одной выборке
Наименование = Выборка.Наименование;
ПредставлениеКИ = Выборка.Представление;
КонецЦикла;
2. Использование связи с регистром сведений (для типовых конфигураций БСП)
В современных типовых конфигурациях (1С:ERP, 1С:Управление торговлей, 1С:Бухгалтерия предприятия 3.0 и др.) контактная информация хранятся не в табличных частях справочника, а в регистре сведений РегистрСведений.КонтактнаяИнформация. В таких системах следует выполнять ЛЕВОЕ СОЕДИНЕНИЕ справочника с этим регистром сведений по ссылке объекта или использовать функции программного модуля БСП УправлениеКонтактнойИнформацией.