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

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия
← На главную

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

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

Способ 1. Профилактика: правильная настройка обмена данными (рекомендуемый)

Самый правильный подход — не исправлять последствия, а предотвращать их. Проблема дублей возникает из-за того, что при стандартном обмене система идентифицирует объекты по их внутреннему уникальному идентификатору (ГУИД). В двух разных базах у двух семантически одинаковых объектов (например, у валюты «рубль») будут разные ГУИДы, и при загрузке система воспримет их как два разных элемента.

Решение — настроить правила обмена в «Конвертации данных» (КД) так, чтобы идентификация происходила не по ГУИДу, а по уникальным бизнес-ключам.

Рассмотрим по шагам, как это сделать:

  1. Откройте правила обмена в конфигурации «Конвертация данных».

  2. Для каждого правила конвертации объекта (ПКО), особенно для справочников, перейдите на вкладку «Настройки».

  3. Снимите флажок «Искать объект приемника по внутреннему идентификатору (ГУИД)». Это ключевой шаг, который отключает стандартный механизм.

  4. Вместо этого настройте поиск по полям, которые однозначно определяют элемент с точки зрения бизнеса. Для этого в табличной части «Поля поиска» укажите нужные поля. Состав полей зависит от вида справочника.

Посмотрим на примеры полей для поиска:

После такой настройки при загрузке данных система будет искать в базе-приемнике элемент не по ГУИДу, а по указанным вами полям. Если элемент с таким же ИНН или артикулом уже существует, система обновит его, а не создаст новый. Это полностью решает проблему дублирования.

Способ 2. Реакция: пишем обработку для поиска всех мест с дублями

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

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

Разберем алгоритм по шагам.

Шаг 1. Обход метаданных конфигурации

Чтобы получить список всех справочников, мы можем перебрать коллекцию Метаданные.Справочники. Аналогично для других объектов.


Процедура НайтиДублиВоВсехСправочниках(Команда)
    
    Для Каждого СправочникМетаданные Из Метаданные.Справочники Цикл
        
        // Пропускаем подчиненные справочники для упрощения, 
        // так как их уникальность часто зависит от владельца.
        Если СправочникМетаданные.Владельцы.Количество() > 0 Тогда
            Продолжить;
        КонецЕсли;
        
        // Проверяем, есть ли у справочника реквизит "Наименование"
        Если СправочникМетаданные.Реквизиты.Найти("Наименование") = Неопределено И СправочникМетаданные.ОсновныеРеквизитыПредставления.Количество() = 0 Тогда
            // Если нет наименования, можно попробовать искать по коду
            // или пропустить этот справочник.
            Продолжить; 
        КонецЕсли;
        
        // Здесь будет вызов функции, которая выполнит запрос
        ПроверитьНаличиеДублей(СправочникМетаданные.Имя, "Наименование");
        
    КонецЦикла;
    
КонецПроцедуры

Шаг 2. Динамическое формирование и выполнение запроса

Теперь напишем саму функцию проверки. Она будет принимать имя объекта и имя поля для поиска, конструировать текст запроса и выполнять его.


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

Запустив такую обработку, вы получите в окне сообщений полный список справочников, в которых есть элементы с одинаковыми наименованиями. Это и есть тот «список мест», который был нужен.

Шаг 3. Объединение найденных дублей

Получив список, можно приступать к объединению. Здесь тоже есть два пути.

  1. Ручное объединение. Для каждого справочника из полученного списка вы последовательно запускаете типовую обработку «Поиск и удаление дублей» (находится в разделе «Администрирование» → «Обслуживание»). Это надежный, контролируемый, но довольно медленный способ.

  2. Автоматизированное объединение. Этот способ требует большего программирования, но экономит массу времени при большом количестве дублей. Логика следующая:

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

    Пример вызова процедуры замены ссылок:

    
    // Предположим, мы нашли группу дублей и определили основной элемент
    // ОсновнойЭлемент - это ссылка на правильный элемент, который должен остаться
    // МассивДублей - это массив ссылок на элементы, которые нужно заменить и удалить
    
    Для Каждого Дубль Из МассивДублей Цикл
        Если Дубль <> ОсновнойЭлемент Тогда
            // Вызываем процедуру замены. Название модуля и процедуры может отличаться!
            ОбщегоНазначения.ЗаменитьСсылки(Дубль, ОсновнойЭлемент);
        КонецЕсли;
    КонецЦикла;
    
    // После замены ссылок дубли можно пометить на удаление
    

    Важно! Перед запуском любой обработки, которая вносит массовые изменения в данные, особенно с удалением, обязательно сделайте резервную копию базы данных. Процесс замены ссылок необратим.

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

← На главную