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

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

Как выбрать все элементы справочника в 1С

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

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

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

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

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

В 1С справочник хранится в базе как таблица, а в коде доступен через менеджер Справочники.<ИмяСправочника>. Менеджер предоставляет методы выборки, которые возвращают объект СправочникВыборка — последовательный курсор по записям. Данные читаются по одной записи в цикле Пока Выборка.Следующий() Цикл, что экономит память на больших справочниках.

Альтернатива — язык запросов. Запрос выполняется на стороне СУБД, возвращает готовую таблицу значений и обычно работает быстрее объектного обхода, особенно когда нужны только отдельные поля, а не полноценные объекты. Для чтения данных без изменения запрос почти всегда предпочтительнее.

Выборка всех элементов методом Выбрать()

Базовый вариант выглядит так: Выборка = Справочники.Контрагенты.Выбрать();, затем цикл Пока Выборка.Следующий() Цикл ... КонецЦикла;. Внутри цикла доступны поля текущего элемента через свойства выборки, а метод ПолучитьОбъект() возвращает полноценный объект для изменения.

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

Выборка = Справочники.Номенклатура.Выбрать();

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

Если Выборка.ЭтоГруппа Тогда

Продолжить;

КонецЕсли;

Сообщить(Выборка.Наименование);

КонецЦикла;

Обратите внимание на проверку ЭтоГруппа: в иерархическом справочнике группы тоже попадают в выборку. Если логика рассчитана только на элементы, группы нужно пропускать, иначе обработка попытается работать с папкой как с товаром или контрагентом.

Обход иерархического справочника целиком

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

Выборка = Справочники.Номенклатура.ВыбратьИерархически();

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

Если НЕ Выборка.ЭтоГруппа Тогда

// обработка элемента

КонецЕсли;

КонецЦикла;

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

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

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

Выбрать()

Подходит для неиерархических справочников или выборки внутри одной группы. Ограничение: в иерархическом справочнике вернёт только один уровень.

ВыбратьИерархически()

Обходит все уровни дерева объектным способом. Удобен, когда нужен порядок «группа — содержимое», но медленнее запроса на больших объёмах.

Запрос ВЫБРАТЬ

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

Выбор всех элементов запросом

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

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

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

"ВЫБРАТЬ

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

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

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

|ИЗ

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

|ГДЕ

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

| И НЕ Номенклатура.ЭтоГруппа";

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

Условие НЕ Номенклатура.ЭтоГруппа имеет смысл только для иерархических справочников — в запросах группы и элементы лежат в одной виртуальной таблице. Условие НЕ ПометкаУдаления отсекает объекты, помеченные на удаление, что критично для обменов и отчётов.

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

Фильтрация: пометка удаления, группы, условия

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

Для подчинённых справочников (например, «Единицы измерения» у номенклатуры) выборка всех элементов без указания владельца вернёт записи по всем владельцам сразу. Это допустимо, но часто не то, что нужно: уточняйте владельца через параметр Выбрать(, Владелец) или условие ГДЕ Владелец = &Владелец.

Сложные условия — по реквизитам, по части наименования, по диапазону кодов — эффективнее всего реализуются в запросе. Объектный отбор поддерживает только сравнение на равенство, поэтому условие вида «наименование содержит подстроку» через Выбрать() не задать.

Порядок действий для полной выборки
  1. 1
    Определите, иерархический ли справочник (посмотрите свойства в конфигураторе или проверьте ЭтоГруппа в отладчике)
  2. 2
    Выберите инструмент: запрос для чтения данных, ВыбратьИерархически() для объектного обхода дерева
  3. 3
    Добавьте фильтр по ПометкаУдаления, если помеченные объекты не должны попасть в результат
  4. 4
    Исключите группы через ЭтоГруппа, если нужны только элементы
  5. 5
    Проверьте результат: количество записей и отсутствие групп и помеченных элементов

Производительность и безопасная обработка больших справочников

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

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

Для проверки логики перед полным запуском ограничьте выборку: в запросе добавьте ВЫБРАТЬ ПЕРВЫЕ 100, убедитесь, что обработка отрабатывает корректно, и только потом снимайте ограничение.

Типичные ошибки при выборке элементов

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

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

Типичные ошибки
01
Использование Выбрать() для иерархического справочника — в результат попадает только один уровень, элементы внутри папок теряются
02
Отсутствие фильтра по ПометкаУдаления — в выгрузки и отчёты попадают объекты, ожидающие удаления
03
Вызов ПолучитьОбъект() для каждого элемента при простом чтении — резкое падение производительности на больших справочниках
04
Изменение данных внутри цикла по той же выборке без получения объекта — попытка записать через выборку невозможна, нужен объект
05
Игнорирование владельца в подчинённом справочнике — выборка смешивает элементы разных владельцев

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

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

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

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

Совпадает с количеством элементов в списке справочника (с учётом фильтров)

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

Записей заметно меньше — вероятно, потерян нижний уровень иерархии или сработали права

Наличие групп в результате
Норма

Группы присутствуют или отсутствуют осознанно, по замыслу обработки

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

Группы попали в обработку элементов и вызывают ошибки при обращении к реквизитам

Помеченные на удаление
Норма

Отфильтрованы условием НЕ ПометкаУдаления

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

В выгрузке присутствуют объекты, помеченные на удаление

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

Как выбрать все элементы справочника, включая группы?

Используйте запрос без условия по ЭтоГруппа: ВЫБРАТЬ Ссылка ИЗ Справочник.ИмяСправочника. Запрос вернёт и группы, и элементы всех уровней. Различить их можно по полю ЭтоГруппа в результате.

Почему Выбрать() возвращает не все элементы?

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

Как исключить помеченные на удаление элементы?

В запросе добавьте условие ГДЕ НЕ ПометкаУдаления. В объектной выборке отбор по пометке удаления через параметр «Отбор» не поддерживается напрямую — проверяйте свойство Выборка.ПометкаУдаления внутри цикла и пропускайте такие элементы.

Что быстрее: Выбрать() или запрос?

Запрос быстрее практически всегда, особенно на клиент-серверной базе: он выполняется одним обращением к СУБД и передаёт только нужные поля. Объектная выборка оправдана, когда нужен порядок обхода дерева или постепенная обработка без загрузки результата в память.

Как выбрать все элементы подчинённого справочника?

Без указания владельца Выбрать() и запрос вернут элементы всех владельцев. Для конкретного владельца передайте его вторым параметром в Выбрать(, Владелец) или добавьте в запрос условие ГДЕ Владелец = &Владелец.

Итог

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

Для чтения всех элементов справочника используйте запрос с фильтрами по ПометкаУдаления и ЭтоГруппа; для объектного обхода иерархии — ВыбратьИерархически(). Не вызывайте ПолучитьОбъект() без необходимости, проверяйте права и тестируйте массовые обработки на копии базы.