Как в 1С массово заполнить реквизит справочника на основании наименования другого объекта?

Программист IT и автоматизация бизнеса
← На главную

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

Способ 1: Использование перебора объектов и поиска по наименованию

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


Процедура ЗаполнитьРеквизитыСотрудников()
    // Создаем запрос для получения списка пользователей
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Пользователи.Ссылка КАК Ссылка
        |ИЗ
        |   Справочник.Пользователи КАК Пользователи
        |ГДЕ
        |   Пользователи.ПометкаУдаления = ЛОЖЬ";
    
    РезультатЗапроса = Запрос.Выполнить();
    ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();

    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
        // Получаем объект для редактирования
        ОбъектПользователь = ВыборкаДетальныеЗаписи.Ссылка.ПолучитьОбъект();
        
        // Пытаемся найти сотрудника по точному совпадению наименования
        НайденныйСотрудник = Справочники.Сотрудники.НайтиПоНаименованию(ОбъектПользователь.Наименование, Истина);
        
        // Проверяем, что сотрудник найден и ссылка не пустая
        Если ЗначениеЗаполнено(НайденныйСотрудник) Тогда
            ОбъектПользователь.СотрудникИзЗУП = НайденныйСотрудник;
            
            Попытка
                ОбъектПользователь.Записать();
                Сообщить("Обработан пользователь: " + ОбъектПользователь.Наименование);
            Исключение
                Сообщить("Ошибка при записи пользователя " + ОбъектПользователь.Наименование + ": " + ОписаниеОшибки());
            КонецПопытки;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Важные нюансы этого подхода:

  1. Производительность: Метод НайтиПоНаименованию внутри цикла создает отдельный запрос к базе данных на каждой итерации. Если пользователей тысячи, это существенно замедлит работу.
  2. Точность поиска: По умолчанию поиск может быть нечетким. Параметр Истина во втором аргументе функции НайтиПоНаименованию гарантирует поиск по полному соответствию.
  3. Лишние записи: Если реквизит уже заполнен, перезаписывать объект не имеет смысла. Проанализируем, как это оптимизировать далее.

Способ 2: Оптимизация через левое соединение в запросе

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


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

В данном примере мы используем ЛЕВОЕ СОЕДИНЕНИЕ по полю Наименование. Это позволяет нам сразу получить готовую пару "Пользователь - Сотрудник". Также мы добавили условие Пользователи.СотрудникИзЗУП = ЗНАЧЕНИЕ(Справочник.Сотрудники.ПустаяСсылка), чтобы обрабатывать только незаполненные элементы.

Использование свойства ОбменДанными.Загрузка

При массовом изменении данных крайне рекомендуется устанавливать свойство ОбменДанными.Загрузка = Истина перед вызовом метода Записать(). Рассмотрим преимущества этого приема:

Обработка спорных моментов: ЗначениеЗаполнено() и пустые ссылки

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

Для ссылочных типов (таких как СправочникСсылка), функция ЗначениеЗаполнено() вернет Ложь, если ссылка является пустой (то есть не указывает на конкретный элемент в базе). Если же ссылка содержит уникальный идентификатор (GUID), функция вернет Истина.

Важно: Не путайте "пустую ссылку" и Неопределено. Большинство методов поиска в 1С возвращают именно пустую ссылку соответствующего типа, поэтому ЗначениеЗаполнено() является универсальным и надежным способом проверки.

Способ 3: Групповое изменение реквизитов (без кода)

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

  1. Откроем обработку "Групповое изменение реквизитов" (обычно находится в разделе Администрирование - Обслуживание).
  2. Выберем объект Пользователи.
  3. Нажмем "Дополнительные параметры" и включим возможность изменения служебных реквизитов.
  4. В списке реквизитов найдем нужный нам параметр и выберем вариант заполнения "По формуле" (если доступно) или воспользуемся встроенным инструментом сопоставления.

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

Рекомендации по работе с данными

Проанализируем риски при поиске по наименованию. Основная проблема — это лишние пробелы. "Иванов Иван" и "Иванов Иван " — это разные строки для базы данных. Перед сопоставлением рекомендуется выполнять нормализацию данных, используя функцию СокрЛП() (удаление пробелов слева и справа) или выполнять подобные операции в самом тексте запроса через ПОДСТРОКА или функции ПОДОБНО (хотя это может снизить производительность индексированного поиска).

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

← На главную