Как исправить ошибку «Запись не верна! Набор записей должен содержать ровно 1 запись» при появлении дублей в регистрах 1С

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

В процессе работы с конфигурациями на платформе 1С:Предприятие 8.3 (такими как КА 2, ERP 2 или ЗУП 3) технические специалисты иногда сталкиваются со странной и пугающей ошибкой: «Запись не верна! Набор записей, принадлежащий менеджеру записи, должен содержать ровно 1 запись». Эта проблема блокирует работу с документами (например, «Прием на работу») или препятствует открытию форм настроек. В этой статье мы подробно разберем, почему возникает эта ситуация, как проанализировать проблемные регистры и какими способами можно устранить дубли в базе данных.

Почему в непериодическом регистре появляются две одинаковые записи?

Прежде чем переходить к лечению, разберем этиологию «болезни». Обычно ошибка возникает в непериодических регистрах сведений, в которых отсутствуют измерения. Такие регистры в типовых конфигурациях 1С используются для хранения глобальных настроек или констант (например, НастройкиШтатногоРасписания, НастройкиУчетаВремени). Логика платформы подразумевает, что в таком регистре может быть только одна-единственная запись.

Рассмотрим причины возникновения дублей:

  1. Особенности работы PostgreSQL: В отличие от MS SQL Server, СУБД PostgreSQL позволяет вставлять абсолютно идентичные строки в таблицу, если на уровне базы данных для нее не определен первичный ключ или уникальный индекс. В 1С для регистров без измерений уникальный индекс может не создаваться, что открывает лазейку для появления полных копий строк при сбоях.
  2. Ошибки платформы: В версиях платформы 8.3.12–8.3.15 наблюдались программные ошибки, при которых механизм «Менеджера записи» некорректно обрабатывал транзакции. Вместо обновления существующей записи (UPDATE) платформа выполняла вставку новой (INSERT).
  3. Сбои при обмене данными: При некорректной загрузке данных через механизмы обмена (особенно если отключены проверки) в базу могут «прилететь» записи, нарушающие логическую целостность системы (в таких случаях бывает полезна очистка записей регистров по битым документам).

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

Способ 1: Программное удаление одной из записей

Если нам удалось программно прочитать набор записей, мы можем попытаться удалить одну лишнюю строку. Этот метод сработает, если метод Прочитать() не вызывает ошибку немедленно. Проанализируем пример кода, который позволяет точечно удалить дубль:


НаборЗаписей = РегистрыСведений.НастройкиУчетаВремени.СоздатьНаборЗаписей();
НаборЗаписей.Прочитать();

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

Важно помнить: этот способ поможет, только если в регистре всего 2 записи. Если их больше, или если платформа блокирует даже чтение, переходим к следующему варианту.

Способ 2: Полная очистка регистра (рекомендуемый метод)

Если метод Прочитать() вызывает ошибку «Набор записей должен содержать ровно 1 запись», значит, мы не можем загрузить данные в память для манипуляций. В этом случае выясним причину: платформа блокирует чтение, так как нарушена логика «одна запись на менеджер». Решением будет полная очистка таблицы регистра и создание записи заново.

Разберем алгоритм действий:

  1. Создаем пустой набор записей без вызова метода Прочитать().
  2. Устанавливаем признак ОбменДанными.Загрузка = Истина.
  3. Записываем пустой набор. Это приведет к выполнению команды DELETE на уровне СУБД для всех записей этого регистра.

Набор = РегистрыСведений.НастройкиШтатногоРасписания.СоздатьНаборЗаписей();
// Набор.Прочитать(); <-- ЭТОТ МЕТОД НЕ ВЫЗЫВАЕМ, он вызывает ошибку
Набор.ОбменДанными.Загрузка = Истина;
Набор.Записать(); // Теперь таблица в СУБД абсолютно пуста

После выполнения этого кода вам нужно зайти в пользовательский интерфейс программы (Настройки — Параметры учета) и заново установить нужные флажки. При сохранении настроек 1С создаст одну корректную запись.

Способ 3: Массовый поиск и исправление «задвоенных» регистров

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

Рассмотрим код для массовой обработки:


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

Способ 4: Исправление на уровне СУБД (PostgreSQL)

Если программные методы из 1С не помогают (что бывает крайне редко, но возможно при сильном повреждении таблиц), задачу можно решить прямым SQL-запросом через pgAdmin или консоль psql.

Внимание: любые действия напрямую в базе данных требуют наличия свежей резервной копии!

Сначала выясним имя таблицы в СУБД. Это можно сделать с помощью функции ПолучитьСтруктуруХраненияБазыДанных(). Допустим, наш регистр называется _inforg1234. В PostgreSQL есть скрытое системное поле ctid, которое является физическим адресом строки. Мы можем использовать его, чтобы удалить одну из двух идентичных строк.

Выполним следующий запрос:


DELETE FROM _inforg1234 
WHERE ctid NOT IN (
    SELECT min(ctid) 
    FROM _inforg1234
);

Этот запрос оставит в таблице только ту запись, которая была вставлена первой (с минимальным адресом ctid), и удалит все ее полные копии. Если регистр должен быть гарантированно пустым, можно использовать команду TRUNCATE TABLE _inforg1234;, которая мгновенно очищает таблицу.

Профилактика и рекомендации

Чтобы избежать повторения ситуации, проанализируем следующие рекомендации:

  1. Обновление платформы: Если вы используете релизы веток 8.3.12–8.3.15, крайне рекомендуется обновиться до актуальных версий (8.3.18 и выше). В них механизмы контроля уникальности для регистров без измерений были значительно доработаны.
  2. Тестирование и исправление (ТиС): Регулярно запускайте процедуру ТиС. При возникновении подобных ошибок выбирайте пункты «Проверка логической целостности» и «Проверка ссылочной целостности» с параметром «Очищать записи».
  3. Настройка PostgreSQL: Убедитесь, что параметры сервера баз данных соответствуют рекомендациям фирмы «1С», особенно в части лимитов памяти и таймаутов транзакций.

Мы проанализировали проблему дублей в регистрах сведений и рассмотрели четыре различных способа ее решения — от простого программного удаления до прямого вмешательства в СУБД. Выбор метода зависит от тяжести ситуации, но чаще всего полная очистка набора записей с установкой ОбменДанными.Загрузка = Истина является самым быстрым и безопасным выходом.

← На главную