При выполнении процедуры свертки информационной базы 1С специалисты часто сталкиваются с критической ошибкой: «Запись с такими ключевыми полями существует!». Эта проблема чаще всего возникает при попытке сформировать документы ввода остатков или при записи наборов записей в периодические регистры сведений, такие как ЦеныНоменклатуры. В данной статье мы подробно разберем причины возникновения этой ситуации и пошагово рассмотрим методы ее решения, основываясь на практике эксплуатации файловых и клиент-серверных баз данных. Для этой задачи есть универсальный инструмент для свертки и настройки регистров.
специалисты часто сталкиваются с критической ошибкой: «Запись с такими ключевыми полями существует!». Эта проблема чаще всего возникает при попытке сформировать документы ввода остатков или при записи наборов записей в периодические регистры сведений, такие как ЦеныНоменклатуры. В данной статье мы подробно разберем причины возникновения этой ситуации и пошагово рассмотрим методы ее решения, основываясь на практике эксплуатации файловых и клиент-серверных баз данных.
Для начала проанализируем, что именно сообщает нам платформа. Ошибка при вызове метода НаборЗаписей.Записать() означает, что в базе данных уже существует запись, у которой значения всех ключевых полей совпадают с той записью, которую мы пытаемся добавить. Для периодического регистра сведений ключевыми полями являются:
Номенклатура, ТипЦен, Организация и т.д.).Если в настройках регистра установлена периодичность «В пределах дня», то для системы записи от 01.12.2021 00:00:00 и 01.12.2021 14:30:00 будут считаться дублями, так как период обрезается до начала дня. Рассмотрим подробнее основные сценарии, приводящие к конфликту.
Выясним ситуацию: часто свертка базы назначается на начало дня, например, на 01.12.2021 00:00:00 — для этого подойдет инструмент для свертки и проверки остатков базы. Если в этот же день в исходной базе уже были введены какие-то документы или установлены цены, то при попытке обработки создать новую запись на эту же дату возникает конфликт. Процедура свертки пытается «записать» остатки, но регистр «сопротивляется», так как ключевые поля (Дата + Номенклатура + Тип цен) уже заняты.
Рассмотрим вариант решения через смещение даты. Попробуем сдвинуть дату свертки на одну секунду назад — на конец предыдущего периода. Вместо 01.12.2021 00:00:00 используем 30.11.2021 23:59:59. Это позволит развести во времени исторические данные и новые записи остатков, которые формирует обработка.
Проанализируем ситуацию, характерную для файлового варианта (база .1CD). Иногда возникают «фантомные» записи. Вы делаете запрос к базе, и он показывает одну строку, но при попытке записи платформа выдает ошибку дублирования. Это признак нарушения логической и физической целостности таблицы индексов, включая удаление движений по битым ссылкам.
Для решения этой проблемы выполним следующие шаги:
bin установленной платформы). Установим галочку «Исправлять обнаруженные ошибки».Посмотрим на пример кода, который может использоваться внутри обработки свертки для записи набора. Если параметр Замещать установлен в значение Ложь, ошибка неизбежна при наличии любых данных в фильтре:
НаборЗаписей = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Период.Установить(ДатаСвертки);
НаборЗаписей.Отбор.Номенклатура.Установить(ТекНоменклатура);
// Если не использовать НаборЗаписей.Прочитать(),
// то при НаборЗаписей.Записать(Ложь) возникнет ошибка дублирования
НаборЗаписей.Записать(Истина); // Истина очищает старые записи по данному фильтру
Иногда корень зла кроется в самой обработке свертки (удобнее через инструмент для свертки базы на больших объемах). Если алгоритм формирования остатков использует запрос, который не учитывает все измерения регистра, в результат могут попасть две строки, которые выглядят идентично для кода записи, но были разными в базе (например, из-за пустых характеристик).
Проанализируем ситуацию через консоль запросов. Выполним прямой запрос к таблице регистра (не к срезу последних!) с отбором по проблемной номенклатуре:
ВЫБРАТЬ
Цены.Период,
Цены.Номенклатура,
Цены.Цена,
Цены.ТипЦен
ИЗ
РегистрСведений.ЦеныНоменклатуры КАК Цены
ГДЕ
Цены.Номенклатура = &СсылкаНаТовар
И Цены.Период МЕЖДУ &НачалоДня И &КонецДня
Если запрос возвращает две строки на одну и ту же дату с одинаковыми измерениями (в файловой базе такое иногда случается при сбоях), их необходимо удалить вручную или программно перед повторным запуском свертки.
Не стоит забывать про «магическое» поведение 1С, связанное с локальным кэшем метаданных. Если структура регистра менялась или в базе происходили сбои, кэш может хранить неактуальную информацию об индексах. Перед выполнением свертки на большом объеме данных обязательно почистим кэш пользователя, под которым запускается процесс. Самый надежный способ — удалить базу из списка и добавить ее заново, либо вручную очистить папки в %AppData%\1C\1cv8\.
В некоторых случаях, чтобы обойти жесткие проверки платформы при записи (если мы уверены в корректности данных), можно модифицировать код обработки, добавив свойство ОбменДанными.Загрузка. Это отключит выполнение прикладных проверок в модулях набора записей, однако стоит помнить, что уникальность ключевых полей проверяется на уровне СУБД, и этот флаг не всегда спасает от ошибки «Запись с такими ключевыми полями существует!», если конфликт происходит на уровне физического индекса.
НаборЗаписей = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
// Установка фильтров...
НаборЗаписей.ОбменДанными.Загрузка = Истина;
Попытка
НаборЗаписей.Записать();
Исключение
Сообщить("Не удалось записать набор: " + ОписаниеОшибки());
КонецПопытки;
Подведем итог. Если при свертке вы столкнулись с данной ошибкой, придерживайтесь следующего алгоритма действий:
chdbfl.exe, для клиент-серверной — реиндексация средствами MS SQL / PostgreSQL.Помните, что свертка — это сложная операция, требующая монопольного доступа и предварительного создания резервной копии. Тщательный анализ ключевых полей регистра ЦеныНоменклатуры поможет вам быстро локализовать причину конфликта и успешно завершить процедуру очистки базы.