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