При работе с регистром бухгалтерии разработчики и администраторы иногда сталкиваются с нестандартным состоянием данных: на счете задано несколько видов субконто (например, Контрагент, Договор, Документ расчетов), но в конкретной проводке аналитика заполнена некорректно. В физической таблице базы данных вместо штатного пустого значения хранится NULL (например, набор аналитик выглядит как Неопределено / Неопределено / NULL). Попытка отредактировать, отменить проведение или сторнировать такой документ приводит к ошибке СУБД о нарушении уникальности ключей в индексах (Cannot insert duplicate key / Попытка вставки неуникального значения в индекс).
Проанализируем природу этой проблемы, выясним, почему невозможно записать NULL средствами встроенного языка 1С, и подробно разберем рабочие способы восстановления целостности данных.
Выясним основные причины, приводящие к такому поведению системы:
NULL, тогда как штатным пустым значением для составных типов в 1С является Неопределено или пустая ссылка соответствующего типа.NULL нарушает работу уникальных индексов таблиц итогов, что и провоцирует откат транзакции.В объектной модели РегистрБухгалтерииНаборЗаписей коллекция субконто строго типизирована на основании типов плана видов характеристик. Любая попытка присвоить полю значение Null:
Для Каждого Проводка Из НаборПроводок Цикл
Проводка.СубконтоКт[ВидСубконтоДокумент] = Null;
КонецЦикла;
автоматически приводит к приведению типа к Неопределено или пустой ссылке. Создать корректирующую проводку с физическим значением NULL через встроенный язык 1С невозможно. Единственный корректный путь — восстановить штатные пустые значения в исходной проблемной записи.
Рассмотрим наиболее надежный и быстрый способ исправления записей без выгрузки базы данных и без прямого вмешательства в SQL-таблицы. Чтобы обойти ошибку проверки уникальности индексов при перезаписи, временно отключим ведение итогов по регистру бухгалтерии.
Разберем по шагам последовательность действий:
Посмотрим на пример обработки для выполнения этой процедуры:
ИмяРегистра = "Хозрасчетный";
Регистр = РегистрыБухгалтерии[ИмяРегистра];
// Шаг 1. Отключаем использование итогов
Регистр.УстановитьИспользованиеИтогов(Ложь);
// Шаг 2. Перезаписываем проблемный документ
НаборЗаписей = Регистр.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Значение = СсылкаНаПроблемныйДокумент;
НаборЗаписей.Прочитать();
// При необходимости явно инициализируем субконто или просто перезаписываем набор
Для Каждого Запись Из НаборЗаписей Цикл
// Платформа автоматически заполнит отсутствующие субконто значениями Неопределено
КонецЦикла;
НаборЗаписей.Записать();
// Шаг 3. Включаем итоги и пересчитываем их
Регистр.УстановитьИспользованиеИтогов(Истина);
Регистр.ПересчитатьИтоги();
Если нет возможности полностью отключать итоги регистра, можно воспользоваться стандартным механизмом управления периодом итогов:
УстановитьПериодРассчитанныхИтогов).Рассмотрим альтернативный способ, который помогает в ситуациях, когда СУБД блокирует любые операции над таблицей:
.dt).Неопределено и записываем движения.Чтобы убедиться, что в информационной базе не осталось других проводок с незаполненными физическими полями субконто, выполним диагностический запрос. Для этого проверяем наличие записей, где поле субконто не заполнено (ЕСТЬ NULL), при условии, что в плане счетов для соответствующего счета эта аналитика предусмотрена.
После выявления всех подобных документов их следует пакетно перезаписать в цикле при временно отключенных итогах регистра, как показано в первом способе.