Приветствуем вас, уважаемые коллеги! Каждый практикующий специалист в среде «1С:Предприятие» рано или поздно сталкивается с необходимостью наведения порядка в справочниках. Одной из наиболее частых и рутинных задач является слияние дублирующихся элементов номенклатуры. Казалось бы, в типовых конфигурациях (например, в «1С:Бухгалтерия предприятия 3.0») для этого предусмотрена удобная стандартная обработка «Поиск и удаление дублей». Однако на практике процесс часто прерывается неприятной ошибкой: «Запись в регистре сведений с такими ключевыми полями уже существует».
В рамках этой статьи мы подробно разберем, почему возникает данная коллизия на уровне платформы «1С:Предприятие 8», проанализируем архитектурные особенности регистров сведений и изучим пять практических способов решения этой проблемы — от интерактивного исправления до написания собственного программного кода.
Для того чтобы понять природу ошибки, обратимся к теории баз данных 1С. Любой регистр сведений (неважно, периодический он или нет, независимый или подчиненный регистратору) функционирует по строгому правилу уникальности ключевых полей. Ключом уникальности в регистре сведений выступает уникальная комбинация всех его измерений, а для периодических регистров — комбинация измерений и периода (даты и времени).
Давайте разберем конкретную ситуацию на примере регистра сведений ЦеныНоменклатуры или КалькуляцииСебестоимостиПродукции. Допустим, в нашей базе данных по ошибке были созданы два дублирующих друг друга элемента номенклатуры:
Номенклатура 1 (дубликат, который мы хотим удалить)Номенклатура 2 (оригинал, который мы хотим оставить)В регистре цен на определенную дату (например, 01.10.2023) были зарегистрированы цены для обоих этих элементов:
01.10.2023 | Измерение Номенклатура: Номенклатура 1 | Ресурс Цена: 50 руб.01.10.2023 | Измерение Номенклатура: Номенклатура 2 | Ресурс Цена: 75 руб.Когда мы запускаем стандартную обработку поиска и замены дублей, система пытается во всех таблицах базы данных (включая регистры сведений) заменить ссылку на удаляемый элемент Номенклатура 1 ссылкой на правильный элемент Номенклатура 2. При попытке выполнить эту замену в регистре сведений СУБД пытается записать следующую строку:
Период: 01.10.2023 | Измерение Номенклатура: Номенклатура 2 | Ресурс Цена: 50 руб.
Но постойте! В этой таблице уже присутствует запись с абсолютно такими же ключевыми полями (Период: 01.10.2023, Измерение Номенклатура: Номенклатура 2). Платформа 1С категорически не может допустить существования двух строк с одинаковым набором ключевых полей (измерений), так как это нарушает базовую целостность данных и логику индексации СУБД. В результате транзакция аварийно завершается, изменения откатываются, а пользователь видит сообщение об ошибке.
Рассмотрим самый простой и безопасный для неискушенных пользователей метод. Стандартная обработка «Поиск и удаление дублей» из состава Библиотеки Стандартных Подсистем (БСП) не просто выдает ошибку, она также выводит подробный список документов и объектов, в которых найдены ссылки на удаляемый элемент.
Проанализируем наши действия по шагам:
УстановкаЦенНоменклатуры, калькуляции, спецификации или расчеты себестоимости).Номенклатура 1).Номенклатура 2). Если в документе уже есть строка с оригиналом, то дублирующуюся строку следует просто удалить, при необходимости просуммировав количество или скорректировав показатели, чтобы не исказить итоговые суммы документа.Если документов-регистраторов сотни или тысячи, ручная работа превращается в затяжной процесс. В такой ситуации на помощь приходит мощнейший комплекс внешних обработок — «Инструменты разработчика» (широко известный как DevTool1C от автора tormozit).
Разберем, как воспользоваться этим инструментом для обхода нашей проблемы:
Если конфликт возникает в независимом регистре сведений (который не подчинен регистраторам-документам, например, в регистре соответствий, штрихкодов или индивидуальных настроек), мы можем написать небольшую сервисную обработку для автоматического слияния записей.
Рассмотрим пример кода на языке 1С, который решает эту задачу. Нам необходимо прочитать записи по старому значению, скорректировать ключевое поле и записать их с проверкой на существование дублирующего ключа.
// Программный перенос записей в независимом регистре сведений
Процедура СхлопнутьЗаписиРегистра(ИмяРегистра, УдаляемаяНоменклатура, ОставляемаяНоменклатура) Экспорт
МенеджерРегистра = РегистрыСведений[ИмяРегистра];
НаборЗаписейУдаляемой = МенеджерРегистра.СоздатьНаборЗаписей();
// Устанавливаем отбор по удаляемой номенклатуре
НаборЗаписейУдаляемой.Отбор.Номенклатура.Установить(УдаляемаяНоменклатура);
НаборЗаписейУдаляемой.Прочитать();
Для Каждого ЗаписьИзНабора Из НаборЗаписейУдаляемой Цикл
// Проверяем, нет ли уже в базе записи с ОставляемаяНоменклатура и точно такими же остальными измерениями
НаборПроверки = МенеджерРегистра.СоздатьНаборЗаписей();
НаборПроверки.Отбор.Номенклатура.Установить(ОставляемаяНоменклатура);
// Пробегаемся по остальным измерениям регистра динамически
Для Каждого Измерение Из Метаданные.РегистрыСведений[ИмяРегистра].Измерения Цикл
ИмяИзмерения = Измерение.Имя;
Если ИмяИзмерения <> "Номенклатура" Тогда
НаборПроверки.Отбор[ИмяИзмерения].Установить(ЗаписьИзНабора[ИмяИзмерения]);
КонецЕсли;
КонецЦикла;
// Если регистр периодический, устанавливаем отбор по периоду
Если Метаданные.РегистрыСведений[ИмяРегистра].Периодичность <> Метаданные.Свойства.ПериодичностьРегистраСведений.Непериодический Тогда
НаборПроверки.Отбор.Период.Установить(ЗаписьИзНабора.Период);
КонецЕсли;
НаборПроверки.Прочитать();
Если НаборПроверки.Количество() > 0 Тогда
// Запись с такими ключевыми полями уже существует.
// В данном случае мы просто игнорируем старую запись, чтобы избежать конфликта уникальности
Сообщить("Конфликт уникальности разрешен: запись по " + СокрЛП(УдаляемаяНоменклатура) + " удалена.");
Иначе
// Записи с новой номенклатурой нет. Мы можем безопасно перезаписать старую запись, изменив измерение
НовыйНабор = МенеджерРегистра.СоздатьНаборЗаписей();
НовыйНабор.Отбор.Номенклатура.Установить(УдаляемаяНоменклатура);
Для Каждого Измерение Из Метаданные.РегистрыСведений[ИмяРегистра].Измерения Цикл
ИмяИзмерения = Измерение.Имя;
Если ИмяИзмерения <> "Номенклатура" Тогда
НовыйНабор.Отбор[ИмяИзмерения].Установить(ЗаписьИзНабора[ИмяИзмерения]);
КонецЕсли;
КонецЦикла;
Если Метаданные.РегистрыСведений[ИмяРегистра].Периодичность <> Метаданные.Свойства.ПериодичностьРегистраСведений.Непериодический Тогда
НовыйНабор.Отбор.Период.Установить(ЗаписьИзНабора.Period);
КонецЕсли;
НовыйНабор.Прочитать();
Если НовыйНабор.Количество() > 0 Тогда
НовыйНабор[0].Номенклатура = ОставляемаяНоменклатура;
Попытка
НовыйНабор.Записать();
Исключение
ВызватьИсключение "Ошибка при перезаписи: " + ОписаниеОшибки();
КонецПопытки;
КонецЕсли;
КонецЕсли;
КонецЦикла;
// В завершение полностью очищаем набор записей по старой номенклатуре
НаборЗаписейУдаляемой.Очистить();
НаборЗаписейУдаляемой.Записать();
КонецПроцедуры
Этот алгоритм позволяет корректно и безболезненно "схлопнуть" независимый регистр сведений, удалив дублирующиеся строки и обновив те, по которым еще нет записей с оригинальной номенклатурой. Чтобы не писать код вручную, можно применить универсальную обработку для удаления и корректировки записей регистров сведений по фильтрам.
Если регистр сведений подчинен регистратору (как в случае с КалькуляцииСебестоимостиПродукции, где записи делаются только документами), напрямую редактировать записи регистра нельзя. Изменения нужно вносить исключительно в сами документы.
Рассмотрим стратегию автоматизации этого процесса с помощью программного кода:
Номенклатура 1.ПолучитьОбъект().Номенклатура 1. Если в этой же табличной части на тех же условиях (например, по той же спецификации) уже присутствует Номенклатура 2, мы объединяем их количественные и суммовые показатели в одну строку, а строку с Номенклатура 1 удаляем из таблицы.Номенклатура 2 нет, мы просто перезаписываем ячейку, меняя ссылку на правильную.Очень часто дубли номенклатуры появляются из-за ошибок синхронизации данных (например, при обмене между конфигурациями «Управление торговлей» и «Бухгалтерия предприятия»). Чтобы оперативно находить расхождения в учете после подобных сеансов обмена, можно использовать программу для автоматического сравнения проводок между базами 1С.
Проанализируем этот важный аспект:
СоответствиеОбъектовДляОбмена.Чтобы минимизировать появление подобных ошибок в будущем, мы рекомендуем придерживаться следующих правил:
Надеемся, что предложенные нами методики помогут вам быстро и безболезненно навести порядок в вашей базе данных 1С! Для комплексного аудита и устранения повторяющихся элементов также подойдёт инструмент для поиска и безопасного удаления дублей с заменой ссылок.