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

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

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

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

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

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

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

Базовый способ: Выгрузить() и ВыгрузитьКолонку()

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

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Номенклатура.Ссылка КАК Ссылка

|ИЗ

| Справочник.Номенклатура КАК Номенклатура

|ГДЕ

| НЕ Номенклатура.ПометкаУдаления";

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

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

МассивСсылок = ТаблицаРезультата.ВыгрузитьКолонку("Ссылка");

Обратите внимание на имя колонки: оно должно совпадать с псевдонимом поля в тексте запроса. Если поле в запросе не имеет явного псевдонима, платформа присваивает имя автоматически (например, «Ссылка» для поля ссылки), но надёжнее всегда задавать псевдоним через КАК — тогда код не сломается при изменении текста запроса.

Признак успешного выполнения: ТипЗнч(МассивСсылок) возвращает тип «Массив», а МассивСсылок.Количество() равно числу строк результата запроса. Если массив пуст, сначала проверьте, что запрос вообще что-то вернул: РезультатЗапроса.Пустой.

Получение массива обходом выборки

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

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Заказы.Ссылка КАК Ссылка,

| Заказы.Сумма КАК Сумма

|ИЗ

| Документ.ЗаказКлиента КАК Заказы";

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

МассивКрупныхЗаказов = Новый Массив;

Пока Выборка.Следующий() Цикл

Если Выборка.Сумма > 100000 Тогда

МассивКрупныхЗаказов.Добавить(Выборка.Ссылка);

КонецЕсли;

КонецЦикла;

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

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

Массив из нескольких колонок и составные структуры

Часто одного значения из строки недостаточно — нужна пара «ссылка и сумма» или набор из трёх-четырёх полей. Здесь массив заполняют структурами, а не отдельными значениями.

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

МассивДанных = Новый Массив;

Пока Выборка.Следующий() Цикл

СтрокаДанных = Новый Структура("Ссылка, Сумма, Контрагент");

ЗаполнитьЗначенияСвойств(СтрокаДанных, Выборка);

МассивДанных.Добавить(СтрокаДанных);

КонецЦикла;

Метод ЗаполнитьЗначенияСвойств() копирует значения из текущей строки выборки в структуру по совпадающим именам. Это работает, только если имена полей выборки совпадают с ключами структуры — ещё один аргумент в пользу явных псевдонимов полей в запросе.

Альтернатива — вообще не собирать массив, а работать с выгруженной таблицей значений: у неё есть поиск, сортировка, свёртка и итоги. Массив структур оправдан, когда результат нужно сериализовать (например, передать в JSON для веб-сервиса) или вернуть из функции в упрощённом виде, не таща за собой таблицу значений.

Сравнение способов

ВыгрузитьКолонку()

Самый короткий код для одной колонки. Нужна промежуточная таблица значений в памяти. Не подходит для отбора строк по условию вне запроса.

Обход выборки в цикле

Гибкая фильтрация и преобразование значений, меньше памяти на больших выборках. Кода больше, фильтрация в цикле медленнее, чем в запросе.

Массив структур

Подходит для нескольких полей и дальнейшей сериализации. Требует аккуратного совпадения имён полей и ключей структуры.

Пакетные запросы и временные таблицы

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

Запрос = Новый Запрос;

Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;

Запрос.Текст =

"ВЫБРАТЬ

| Товары.Ссылка КАК Ссылка

|ПОМЕСТИТЬ ВТ_Товары

|ИЗ

| Справочник.Номенклатура КАК Товары

|;

|

|ВЫБРАТЬ

| ВТ.Ссылка КАК Ссылка

|ИЗ

| ВТ_Товары КАК ВТ";

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

// Результаты[0] — результат помещения во временную таблицу

// Результаты[1] — итоговая выборка

МассивСсылок = Результаты[1].Выгрузить().ВыгрузитьКолонку("Ссылка");

Обращение по индексу требует аккуратности: индексация массива результатов начинается с нуля, и порядок соответствует порядку запросов в тексте. При изменении текста пакета индексы легко «уезжают» — после правок проверяйте, что берёте результат именно того запроса.

Массив как параметр запроса: обратная задача

Частый сценарий — получить массив из одного запроса и передать его в другой для отбора. Платформа умеет сравнивать поле с массивом через оператор В:

Запрос2 = Новый Запрос;

Запрос2.Текст =

"ВЫБРАТЬ

| Остатки.Номенклатура КАК Номенклатура,

| Остатки.КоличествоОстаток КАК Остаток

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Остатки(, Номенклатура В (&МассивТоваров)) КАК Остатки";

Запрос2.УстановитьПараметр("МассивТоваров", МассивСсылок);

Параметр принимает массив, список значений и таблицу значений. Для больших списков (тысячи элементов) эффективнее не передавать массив в условие В, а поместить данные во временную таблицу и соединиться с ней — это снижает нагрузку на СУБД и упрощает план запроса. Также помните, что в параметр нельзя передавать массив со значениями NULL в смешанном виде без учёта логики сравнения: сравнение с NULL в запросах работает через ЕСТЬ NULL, а не через В.

Производительность и расход памяти

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

Ещё одна ловушка — выборка поля Ссылка вместе с десятком ненужных полей «про запас». Каждое лишнее поле увеличивает и время выполнения запроса, и объём выгружаемых данных. Формулируйте список полей строго под задачу: если нужен массив ссылок, выбирайте только ссылку.

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

Типичные ошибки
01
Обращение к колонке по имени поля без псевдонима: после правки запроса имя меняется, и ВыгрузитьКолонку() вызывает исключение. Всегда задавайте псевдоним через КАК.
02
Вызов ВыгрузитьКолонку() у результата запроса, а не у таблицы значений: метод принадлежит таблице значений, сначала нужен Выгрузить().
03
Игнорирование проверки РезультатЗапроса.Пустой: при пустом результате массив будет пустым, и последующая логика может отработать некорректно без явной ошибки.
04
Выборка лишних полей в запросе: лишние колонки замедляют запрос и раздувают таблицу значений в памяти.
05
Неверный индекс при ВыполнитьПакет(): после добавления запроса в пакет индексы результатов сдвигаются, и массив собирается не из той выборки.

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

Минимальный контроль после получения массива — проверить тип и количество элементов. В отладчике достаточно остановиться после строки выгрузки и посмотреть значение переменной: у массива видно число элементов и содержимое по индексам.

Если ТипЗнч(МассивСсылок) <> Тип("Массив") Тогда

ВызватьИсключение "Ожидался массив из результата запроса";

КонецЕсли;

Если МассивСсылок.Количество() = 0 Тогда

// Обработка пустого результата: запись в журнал, уведомление, пропуск операции

КонецЕсли;

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

При подозрении на неправильный отбор проверяйте сам запрос в консоли запросов до переноса в код: так вы отделите ошибки текста запроса от ошибок обработки результата.

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

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

Тип переменной после выгрузки
Норма

ТипЗнч() возвращает «Массив»

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

Возвращается «ТаблицаЗначений» — пропущен вызов ВыгрузитьКолонку()

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

Равно числу строк результата запроса

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

Меньше ожидаемого — проверьте условия отбора и логику цикла

Имя колонки
Норма

Совпадает с псевдонимом поля в тексте запроса

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

Исключение «Колонка не найдена» при вызове ВыгрузитьКолонку()

Пустой результат
Норма

РезультатЗапроса.Пустой = Ложь перед обработкой

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

Массив пуст, хотя данные в базе есть — проверяйте параметры и условия запроса

Итог

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

Массив из запроса получают через Выгрузить().ВыгрузитьКолонку("ИмяКолонки") или ручным обходом выборки. Псевдонимы полей задавайте явно, проверяйте результат на пустоту, а для больших списков отбора используйте временные таблицы вместо передачи огромного массива в параметр.

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

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

Да: Массив = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");. Такая цепочка рабочая, но при отладке удобнее разбить её на отдельные строки — проще проверить результат запроса и таблицу значений по отдельности.

Чем ВыгрузитьКолонку() отличается от обхода выборки в цикле?

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

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

Проще всего применить РАЗЛИЧНЫЕ в тексте запроса — тогда дубликаты отсечёт СУБД. Если массив уже получен, дубликаты удаляют через соответствие: значения добавляют как ключи, затем выгружают ключи обратно в массив.

Почему ВыгрузитьКолонку() выдаёт ошибку «Колонка не найдена»?

Имя, переданное в метод, не совпадает с именем колонки таблицы значений. Проверьте псевдоним поля в запросе: колонка называется так, как поле названо после КАК. Регистр букв значения не имеет, а лишние пробелы и опечатки — имеют.

Можно ли передать массив в запрос для отбора?

Да: установите массив как параметр через УстановитьПараметр() и используйте оператор В (&ИмяПараметра) в условии. Для очень больших списков эффективнее поместить значения во временную таблицу и выполнить соединение.

Что вернёт ВыполнитьПакет() и как взять нужный результат?

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