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

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При разработке конфигураций и отчетов на платформе 1С перед программистом часто встает задача обойти все элементы справочника или проанализировать данные по всем элементам, если пользователь не указал конкретный отбор. Разберем основные подходы к решению этой задачи, сравним производительность методов и выясним, как правильно строить условия в запросах.

Вариант 1. Обход справочника через метод Выбрать()

Для последовательного перебора элементов справочника встроенный язык 1С предоставляет метод Выбрать менеджера справочника. Этот метод создает объект ВыборкаИзРезультатаЗапроса, по которому можно итерироваться в цикле.

Рассмотрим пример кода для обхода и изменения наименования элементов:


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

Проанализируем особенности этого способа:

  1. Считывание избыточных данных: Метод Выбрать() считывает из базы данных всю таблицу целиком со всеми реквизитами, включая тяжелые поля и табличные части. Если для анализа вам требуется всего пара полей (например, Ссылка и Наименование), метод создаст лишнюю нагрузку на оперативную память и сеть.
  2. Иерархия и пометки удаления: При стандартной выборке в цикл попадают как элементы, так и группы справочника, а также помеченные на удаление объекты.
  3. Нагрузка при модификации: Если в цикле вызываются методы ПолучитьОбъект() и Записать() для десятков тысяч элементов, запись в одной неявной транзакции может привести к длительным блокировкам таблиц. В таких сценариях рекомендуется выполнять запись порциями с явным вызовом НачатьТранзакцию() и ЗафиксироватьТранзакцию() каждые 100–1000 записей.

Вариант 2. Получение данных с помощью запроса

Если задача сводится только к чтению и анализу данных, наиболее производительным и надежным решением является использование языка запросов 1С. Запрос позволяет выбрать только строго необходимые реквизиты и сразу отсечь ненужные записи.

Посмотрим на пример запроса для выборки всех действующих элементов:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Контрагенты.Ссылка КАК Контрагент,
    |	Контрагенты.Наименование КАК Наименование,
    |	Контрагенты.ИНН КАК ИНН
    |ИЗ
    |	Справочник.Контрагенты КАК Контрагенты
    |ГДЕ
    |	НЕ Контрагенты.ЭтоГруппа
    |	И НЕ Контрагенты.ПометкаУдаления";

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
    // Обработка полученных данных
КонецЦикла;

Вариант 3. Реализация условия «Один элемент или все» в запросе

Частая практическая ситуация: на форме отчета есть поле выбора контрагента. Если пользователь выбрал конкретного контрагента, отчет строится по нему; если поле оставлено пустым — отчет строится по всей базе.

Разберем три способа реализации такого поведения.

Способ А. Программная модификация текста запроса

Если контрагент не задан, условие ГДЕ исключается из текста запроса перед выполнением. Проверить заполненность реквизита на форме можно функцией ЗначениеЗаполнено().


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Контрагенты.Ссылка КАК Ссылка
    |ИЗ
    |	Справочник.Контрагенты КАК Контрагенты
    |//УСЛОВИЕ_ОТБОРА
    |";

Если ЗначениеЗаполнено(Контрагент) Тогда
    Запрос.Текст = СтрЗаменить(Запрос.Текст, "//УСЛОВИЕ_ОТБОРА", "ГДЕ Контрагенты.Ссылка = &Контрагент");
    Запрос.УстановитьПараметр("Контрагент", Контрагент);
Иначе
    Запрос.Текст = СтрЗаменить(Запрос.Текст, "//УСЛОВИЕ_ОТБОРА", "");
КонецЕсли;

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

Этот подход гарантирует создание оптимального плана выполнения на уровне СУБД, так как текст SQL-запроса не содержит лишних логических ветвлений.

Способ Б. Использование конструкции ВЫБОР в тексте запроса

Если требуется сохранить неизменный текст запроса, можно использовать проверку на пустую ссылку внутри секции ГДЕ:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Контрагенты.Ссылка КАК Ссылка
    |ИЗ
    |	Справочник.Контрагенты КАК Контрагенты
    |ГДЕ
    |	ВЫБОР
    |		КОГДА &Контрагент = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)
    |			ТОГДА ИСТИНА
    |		ИНАЧЕ Контрагенты.Ссылка = &Контрагент
    |	КОНЕЦ";

Запрос.УстановитьПараметр("Контрагент", Контрагент);
Результат = Запрос.Выполнить();

Важное предостережение по производительности: Конструкция ВЫБОР КОГДА &Параметр = ... ТОГДА ИСТИНА мешает оптимизатору СУБД построить эффективный план с использованием индексов (Index Seek). СУБД часто переходит к полному сканированию таблицы (Table Scan), что на больших объемах данных приводит к резкому замедлению запроса.

Способ В. Работа с виртуальными таблицами и Построителем отчета/СКД

Если данные берутся из регистров (например, остатки взаиморасчетов), критически важно передавать условия не в секцию ГДЕ, а непосредственно в параметры виртуальной таблицы:


// Неправильно (рассчитываются остатки по всей базе, затем фильтруются):
// РегистрНакопления.ВзаиморасчетыСКонтрагентами.Остатки(&Дата, ) ГДЕ Контрагент = &Контрагент

// Правильно (остатки рассчитываются только по нужному контрагенту):
// РегистрНакопления.ВзаиморасчетыСКонтрагентами.Остатки(&Дата, Контрагент = &Контрагент)

Если в запросе присутствуют синтаксические конструкции в фигурных скобках вида {ГДЕ ВзаиморасчетыСКонтрагентамиОстатки.Контрагент.*}, они предназначены для работы с объектом ПостроительЗапроса или Системой компоновки данных (СКД). При вызове стандартного метода Запрос.Выполнить() эти конструкции платформой игнорируются, поэтому накладывать отборы следует через свойства построителя или параметры СКД.

← На главную