К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как выгрузить запрос в список значений в 1С

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

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

Оба подхода корректны, но различаются по скорости, гибкости и объёму кода. Первый быстрее на больших выборках и короче в записи. Второй позволяет на лету формировать представления, пометки, картинки и фильтровать строки. Ниже разобраны оба варианта с готовым кодом, типичными ошибками и способами проверки результата.

Материал ориентирован на управляемые и обычные формы платформы 8.3, синтаксис одинаков для сервера и толстого клиента. На тонком клиенте работа с запросами недоступна — выборку выполняют на сервере, а готовый список передают в форму.

Когда нужен список значений, а не таблица или массив

Список значений — объект с парой «значение + представление», поддерживающий пометки, картинки и сортировку. Его выбирают, когда данные пойдут в интерфейс: в список выбора поля ввода, в диалог ОтметитьЭлементы, в параметр отбора СКД с режимом множественного выбора. Для чисто программной передачи данных между процедурами чаще достаточно массива — он легче и быстрее обходится.

Таблица значений нужна, когда из запроса требуется больше одной колонки. Список значений хранит только одно значение в элементе; если из выборки нужны, например, и ссылка на номенклатуру, и её артикул, и остаток — список не подойдёт, используйте таблицу значений или дерево. Попытка «упаковать» несколько полей в представление через разделитель — распространённая ошибка, которая позже ломается при изменении формата строки.

Способ 1: выгрузка через таблицу значений и ЗагрузитьЗначения

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

bsl
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| НЕ Номенклатура.ПометкаУдаления";

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

СписокНоменклатуры = Новый СписокЗначений;
СписокНоменклатуры.ЗагрузитьЗначения(
 ТаблицаРезультата.ВыгрузитьКолонку("Ссылка"));

Обратите внимание на имя колонки в ВыгрузитьКолонку: оно должно совпадать с псевдонимом поля в тексте запроса (в примере — «Ссылка»). Если псевдоним не задан, платформа сгенерирует имя вида «Ссылка» или «Поле1» по своим правилам, и обращение по несуществующему имени вызовет ошибку «Колонка не найдена». Явные псевдонимы через КАК делают код устойчивым.

Этот способ оптимален по скорости: обход результата выполняется внутри платформы, без интерпретации цикла во встроенном языке. На выборках в десятки тысяч строк разница с ручным циклом заметна. Ограничение — нельзя задать представление, пометку или картинку, все элементы получают стандартное строковое представление значения.

Способ 2: обход выборки в цикле

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

bsl
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Контрагенты.Ссылка КАК Ссылка,
| Контрагенты.Наименование КАК Наименование,
| Контрагенты.ИНН КАК ИНН
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| Контрагенты.ЭтоГруппа = ЛОЖЬ";

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

СписокКонтрагентов = Новый СписокЗначений;
Пока Выборка.Следующий() Цикл
 Представление = Выборка.Наименование + " (ИНН " + Выборка.ИНН + ")";
 СписокКонтрагентов.Добавить(Выборка.Ссылка, Представление);
КонецЦикла;

Выборка через Выбрать() последовательная: строки читаются по одной, что экономит память на больших результатах по сравнению с Выгрузить(), который материализует всю таблицу сразу. Если выборка потенциально огромная (сотни тысяч строк), цикл по выборке предпочтительнее — хотя в интерфейс такие объёмы всё равно выводить не стоит.

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

Типовые сценарии применения

Заполнение списка выбора поля ввода

Частая задача — ограничить выбор в поле формы предопределённым набором. Полученный из запроса список присваивают свойству СписокВыбора элемента формы или колонки таблицы. Для динамического обновления при изменении реквизитов запрос переисполняют и список заполняют заново, предварительно очистив его методом Очистить().

Передача списка в параметр другого запроса

Конструкция «В (&Список)» в тексте запроса принимает и массив, и список значений. Если у вас уже есть СписокЗначений, его можно передать напрямую: Запрос.УстановитьПараметр("Список", СписокНоменклатуры). Дополнительная выгрузка в массив не требуется — платформа сама извлечёт значения элементов.

Отбор в динамическом списке и СКД

Для отборов СКД с видом сравнения «В списке» параметр также принимает список значений. Это позволяет построить цепочку: один запрос отбирает ключевые ссылки, они выгружаются в список, список становится параметром отчёта. Такой приём типичен для отчётов вида «продажи по выбранной группе товаров с вложенными подгруппами», где первый запрос разворачивает иерархию.

Маршрут решения

Как выбрать способ выгрузки

Нужны только значения одной колонки, представления стандартныеВыгрузить() + ВыгрузитьКолонку() + ЗагрузитьЗначения()
Нужны составные представления, пометки или фильтрация строкОбход выборки циклом с Добавить()
Нужно несколько колонок из запросаСписок значений не подходит — используйте таблицу значений
Результат очень большой и важна памятьЦикл по выборке через Выбрать() без Выгрузить()

Проверка результата и отладка

После выгрузки проверьте три вещи: количество элементов, тип значений и отсутствие дублей. Количество элементов возвращает метод Количество() — его удобно сверить с ожидаемым числом строк запроса. Тип значений проверяется в отладчике: элемент списка должен содержать ссылку нужного типа, а не строку с наименованием, если дальше список пойдёт в отбор по ссылкам.

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

Контрольные точки

Как проверить результат

Количество элементов списка
Норма

Совпадает с числом строк результата запроса

Тревожный признак

Список пуст или элементов больше, чем строк в выборке

Тип значения элемента
Норма

Ссылка нужного типа или ожидаемый примитивный тип

Тревожный признак

Строка вместо ссылки, значение NULL

Дубли значений
Норма

Каждое значение встречается один раз

Тревожный признак

Повторы из-за соединения таблиц без РАЗЛИЧНЫЕ

Представления
Норма

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

Тревожный признак

Пустые представления или технические GUID

Типичные ошибки и ограничения

Самая частая ошибка — попытка вызвать ВыгрузитьКолонку у выборки: метод есть только у таблицы значений, полученной через Выгрузить(). Вторая по частоте — несовпадение имени колонки с псевдонимом в запросе, особенно когда поле выбирается через точку (Номенклатура.Ссылка) и разработчик ожидает колонку с точкой в имени, а платформа даёт имя последнего поля.

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

Типичные ошибки
01
Вызов ВыгрузитьКолонку у выборки вместо таблицы значений — метод недоступен, возникает ошибка
02
Имя колонки не совпадает с псевдонимом в запросе — ошибка «Колонка не найдена»
03
Отсутствие РАЗЛИЧНЫЕ в запросе — дубли значений в списке
04
Выгрузка ссылки как строки — список не работает в отборах по ссылке
05
Выполнение запроса на тонком клиенте — методы запроса недоступны вне сервера

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

Производительность и объёмы данных

Для выборок до нескольких тысяч строк разница между способами незаметна — выбирайте по удобству кода. На десятках тысяч строк вариант с ВыгрузитьКолонку быстрее, но требует памяти под полную таблицу результата. Цикл по выборке медленнее в интерпретации, зато не держит весь результат в памяти одновременно.

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

Если список нужен только как параметр запроса с условием «В (&Параметр)», промежуточный СписокЗначений часто вообще не нужен — передайте массив из ВыгрузитьКолонку напрямую в УстановитьПараметр. Это убирает один объект и упрощает код.
ПЗ
Практическое замечание

Частые вопросы

Можно ли выгрузить запрос в список значений одним методом без цикла и таблицы?

Нет, встроенный язык не содержит прямого метода. Минимальная цепочка — Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Поле") с последующей передачей массива в ЗагрузитьЗначения. Это фактически одна строка кода заполнения списка.

Как выгрузить в список значений два поля запроса?

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

Почему в списке появляются повторяющиеся элементы?

Запрос возвращает дубли — например, при выборке из регистра сведений без группировки или при соединении таблиц «один ко многим». Добавьте РАЗЛИЧНЫЕ после ВЫБРАТЬ или сгруппируйте результат. Список значений сам уникальность не контролирует.

Как задать пометки элементам при выгрузке?

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

Работает ли выгрузка на тонком клиенте?

Нет, объект Запрос недоступен на тонком клиенте. Формируйте список в серверной процедуре формы или в модуле менеджера объекта и возвращайте готовый СписокЗначений — он корректно передаётся между сервером и клиентом.

Что быстрее: цикл по выборке или ВыгрузитьКолонку?

На больших объёмах ВыгрузитьКолонку быстрее, так как обход выполняется внутри платформы, а не интерпретатором встроенного языка. Но Выгрузить() материализует всю таблицу в памяти, поэтому при очень больших выборках цикл по выборке может быть предпочтительнее по расходу памяти.

Итог

Что важно запомнить

Прямой выгрузки запроса в СписокЗначений нет: используйте Выгрузить().ВыгрузитьКолонку() с ЗагрузитьЗначения для простых случаев и цикл по выборке с Добавить(), когда нужны представления и пометки. Следите за псевдонимами колонок, добавляйте РАЗЛИЧНЫЕ против дублей и выполняйте запрос только на сервере.