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

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

Как работает выборка в 1С

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

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

Термин «выборка» в 1С имеет двойной смысл. Во-первых, это результат выполнения запроса — объект ВыборкаИзРезультатаЗапроса, по которому можно последовательно пройтись в цикле. Во-вторых, это выборка из таблицы объекта (справочника, документа, регистра), получаемая методом Выбрать() у менеджера объекта. Оба механизма решают одну задачу — извлечь подмножество записей по заданным условиям, но отличаются по гибкости и производительности.

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

Два способа получить выборку: запрос или метод объекта

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

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

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

Сравнение вариантов

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

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

Метод Выбрать() менеджера объекта

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

Выгрузить() в таблицу значений

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

Как выполнить запрос и получить выборку

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

bsl
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| Номенклатура.Ссылка КАК Товар,
| Номенклатура.Артикул КАК Артикул
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Родитель = &Группа
| И НЕ Номенклатура.ПометкаУдаления";
Запрос.УстановитьПараметр("Группа", ГруппаТоваров);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
 Сообщить(Выборка.Артикул + " — " + Выборка.Товар);
КонецЦикла;

Метод Следующий() перемещает курсор на следующую запись и возвращает Истина, пока записи не закончились. Обращение к полям идёт по именам, заданным в секции ВЫБРАТЬ: Выборка.Артикул, Выборка.Товар. После завершения цикла повторно пройти по той же выборке нельзя — нужно выполнять запрос заново или заранее выгрузить результат.

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

Как обходить результаты: линейно, по группировкам и иерархии

Метод Выбрать() результата запроса принимает параметр — тип обхода. По умолчанию используется линейный обход: записи идут одна за другой в порядке, заданном предложением УПОРЯДОЧИТЬ ПО. Это подходит для большинства задач — заполнения табличных частей, выгрузки данных, пакетной обработки.

Если запрос содержит итоги (предложение ИТОГИ ПО), выборку можно обходить ПоГруппировкам: сначала читается запись группы, затем через вложенную выборку — её детальные записи. Так строят отчёты с подчинёнными уровнями, например «контрагент → документы контрагента». Третий вариант — ПоГруппировкамСИерархией — применяется для иерархических справочников, когда нужно обойти дерево с учётом вложенности элементов.

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

Отборы и параметры: как ограничить выборку

Основной инструмент ограничения выборки — предложение ГДЕ в тексте запроса. Условия могут включать сравнения, проверку вхождения в список (В), проверку на NULL, сравнение по шаблону (ПОДОБНО). Все переменные значения следует передавать только через параметры — конкатенация строк в тексте запроса затрудняет отладку и чревата ошибками при специальных символах в данных.

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

Отдельный случай — виртуальные таблицы регистров: Остатки, Обороты, СрезПоследних. Их параметры (период, условия) задаются в скобках после имени таблицы в тексте запроса, а не в общем предложении ГДЕ. Это критично для производительности: отбор в параметрах виртуальной таблицы отсекает лишние записи до соединения, а фильтр в ГДЕ — после.

Выборка против таблицы значений: что выбрать

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

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

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

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

Как выбрать действие

Данные нужно один раз последовательно обработатьИспользуйте Выбрать() и цикл Пока Выборка.Следующий()
Нужен поиск, сортировка или повторный обход результатаИспользуйте Выгрузить() в таблицу значений
Нужен отчёт с группами и подчинёнными строкамиДобавьте ИТОГИ ПО в запрос и обходите выборку ПоГруппировкам
Результат содержит сотни тысяч строкОбрабатывайте пакетами или через выборку, не выгружая всё в память
Нужно просто перебрать элементы одного справочника по равенству реквизитаИспользуйте метод Выбрать() менеджера объекта с отбором-структурой

Как проверить, что выборка работает правильно

Первая проверка — количество и содержимое записей. В отладчике поставьте точку останова после выполнения запроса и посмотрите результат через Выгрузить() в табличном документе или через вычисление выражения. Сверьте число строк с ожидаемым по данным в пользовательском режиме — расхождение обычно означает ошибку в условиях отбора или соединениях.

Вторая проверка — типы и значения полей. Частая ситуация: поле приходит как NULL из-за левого соединения, а код дальше пытается сравнить его со строкой или числом. Проверяйте такие поля функцией ЗначениеЗаполнено() или явным сравнением с NULL через Есть NULL в запросе.

Третья проверка — скорость. Если запрос к большой таблице выполняется дольше нескольких секунд, включите технологический журнал или замер производительности в конфигураторе и посмотрите, какие операции занимают время. Чаще всего причина — отсутствие индекса по полям отбора, фильтрация после соединения вместо параметров виртуальной таблицы или выборка лишних полей, включая поля составного типа.

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

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

Количество записей в выборке
Норма

Совпадает с числом записей, видимым в пользовательском режиме по тем же условиям

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

Записей больше (дубли из-за соединения) или меньше (лишнее условие в ГДЕ)

Значения полей в цикле
Норма

Поля содержат ожидаемые типы данных, NULL обработан явно

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

Ошибка при обращении к полю или сравнение NULL со значением

Время выполнения запроса
Норма

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

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

Запрос «подвисает» на больших данных, в замере виден полный перебор таблицы

Повторное обращение к выборке
Норма

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

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

Попытка второго обхода той же выборки молча не даёт записей

Типичные ошибки при работе с выборкой

Самая распространённая ошибка — запрос в цикле. Код обходит выборку и на каждой итерации выполняет ещё один запрос, чтобы дотянуть связанные данные. На десяти записях это незаметно, на десяти тысячах — превращается в тысячи обращений к СУБД. Правильное решение — один запрос с соединением таблиц или пакетный запрос с временной таблицей.

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

Типичные ошибки
01
Запрос внутри цикла по выборке — резкое падение производительности; заменяется одним запросом с соединением
02
Повторный обход выборки после цикла — записей нет, ошибка не выдаётся; нужно выгрузить результат заранее
03
Отбор по виртуальной таблице через ГДЕ вместо параметров — лишний перебор данных и блокировки
04
Игнорирование NULL из левых соединений — ошибки сравнения и пустые значения в расчётах
05
Выгрузка огромного результата в таблицу значений — перерасход памяти сервера; нужна пакетная обработка
06
Отладка только под полными правами — у пользователей с RLS выборка возвращает другой набор записей

FAQ: частые вопросы о выборке в 1С

Чем выборка отличается от результата запроса?

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

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

Напрямую — нет, у выборки нет свойства количества. Варианты: выгрузить результат в таблицу значений и посмотреть Количество(), либо выполнить отдельный запрос с функцией КОЛИЧЕСТВО, либо посчитать записи в самом цикле обхода.

Почему выборка возвращает меньше записей, чем видно в списке?

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

Как отсортировать записи в выборке?

Сортировка задаётся предложением УПОРЯДОЧИТЬ ПО в тексте запроса — по одному или нескольким полям с указанием ВОЗР или УБЫВ. В самой выборке порядок изменить нельзя; если нужна другая сортировка после получения данных, выгрузите результат в таблицу значений и используйте метод Сортировать().

Что делать, если нужно обойти выборку дважды?

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

Работает ли выборка в фоновом задании и на сервере?

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

Итог

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

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