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