В процессе сопровождения и обновления программных продуктов «1С:Зарплата и управление персоналом» (ЗУП 3.1) и «1С:Зарплата и кадры государственного учреждения» (ЗиКГУ 3.1) технические специалисты нередко сталкиваются со сбоем на этапе реорганизации базы данных. Платформа выдает критическую ошибку: «Записи регистра сведений стали неуникальными», прерывая процесс обновления конфигурации. Чаще всего проблемным объектом оказывается независимый непериодический регистр сведений СоставДокументовЗарплатаКадры.
В этой статье мы подробно проанализируем, для чего предназначен данный регистр, почему в нем физически могут появляться дублирующие записи, и рассмотрим несколько практических методов устранения этой ошибки — от использования встроенного языка 1С до низкоуровневых запросов на стороне СУБД.
Прежде чем переходить к устранению неполадок, разберем архитектурное назначение этого объекта метаданных. Регистр сведений СоставДокументовЗарплатаКадры является служебным (техническим). Он предназначен для оптимизации работы динамических списков в различных кадровых и расчетных журналах документов (таких как «Все начисления», «Кадровые документы», «Ведомости в банк/кассу» и др.).
В современных конфигурациях на платформе 1С:Предприятие 8.3 активно используется механизм разграничения прав доступа на уровне записей (RLS — Record Level Security). Если бы при открытии списков документов система каждый раз обращалась к табличным частям сотен тысяч документов для фильтрации по конкретному физическому лицу, сотруднику или подразделению, это вызывало бы огромные задержки и блокировки базы данных.
Для решения этой проблемы разработчики спроектировали механизм трансляции состава документов в плоскую таблицу. При записи или проведении любого документа, содержащего сведения о сотрудниках, система автоматически регистрирует связку в регистре СоставДокументовЗарплатаКадры. Динамические списки журналов делают быстрое левое соединение (LEFT JOIN) с этим регистром, мгновенно отсекая документы, к которым у текущего пользователя нет прав доступа, или выполняя быстрые пользовательские отборы.
Измерениями регистра сведений СоставДокументовЗарплатаКадры являются всего два поля:
ФизическоеЛицо (тип СправочникСсылка.ФизическиеЛица)ДокументФизическогоЛица (ссылка на документ, сделавший запись)Поскольку регистр является независимым и непериодическим, сочетание значений этих двух измерений образует уникальный ключ записи СУБД. Платформа физически не допускает существования двух абсолютно одинаковых строк с одинаковым набором измерений.
Однако на практике пользователи часто замечают, что, например, ведомость на одного сотрудника делает две записи в регистр. Разберем причины возникновения таких дублей:
Рассмотрим сценарий: при обновлении конфигурации в Конфигураторе или при попытке вернуться на предыдущий релиз (что делать крайне не рекомендуется без восстановления резервной копии) система аварийно завершает работу.
Это происходит из-за того, что в новой (или старой) версии конфигурации меняется структура регистра сведений (например, изменяется состав или типы измерений). На уровне СУБД платформа пытается пересоздать уникальный индекс таблицы. Если в текущей базе данных уже содержатся дублирующие записи (которые ранее могли быть записаны из-за программного бага), СУБД не может построить индекс по неуникальным полям и прерывает трансляцию изменений.
Ниже мы разберем по шагам три проверенных метода локализации и устранения этой ошибки.
Если ваша информационная база развернута на SQL-сервере (MS SQL Server, PostgreSQL), наиболее быстрым и эффективным решением будет прямая работа с таблицами базы данных.
Сначала нам нужно определить физическое имя таблицы регистра сведений в СУБД. Для этого в конфигураторе воспользуемся функцией ПолучитьСтруктуруХраненияБазыДанных() или выполним поиск по имени объекта метаданных. Предположим, что имя таблицы нашего регистра в СУБД — _InfoRg20542 (где 20542 — уникальный внутренний идентификатор объекта).
Выполним следующий SQL-запрос для поиска записей, нарушающих уникальность:
SELECT f_id, doc_id, COUNT(*)
FROM _InfoRg20542 -- укажите имя таблицы вашего регистра
GROUP BY f_id, doc_id
HAVING COUNT(*) > 1;
Для удаления дубликатов и сохранения только одной уникальной строки можно воспользоваться конструкцией с обобщенным табличным выражением (CTE):
WITH CTE_Duplicates AS (
SELECT f_id, doc_id,
ROW_NUMBER() OVER (PARTITION BY f_id, doc_id ORDER BY (SELECT NULL)) as RowNum
FROM _InfoRg20542
)
DELETE FROM CTE_Duplicates WHERE RowNum > 1;
После выполнения данного запроса на стороне СУБД все дублирующиеся строки будут удалены, и обновление конфигурации в Конфигураторе успешно завершится.
Если база работает в файловом режиме или у вас нет прямого доступа к консоли СУБД, мы можем найти и исправить данные программными средствами 1С. Для этого необходимо запустить базу в пользовательском режиме (на исходном релизе конфигурации до начала обновления) и воспользоваться консолью запросов.
Напишем запрос на встроенном языке 1С для выявления дублирующих записей:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Состав.ФизическоеЛицо КАК ФизическоеЛицо,
| Состав.ДокументФизическогоЛица КАК ДокументФизическогоЛица,
| КОЛИЧЕСТВО(*) КАК Количество
|ИЗ
| РегистрСведений.СоставДокументовЗарплатаКадры КАК Состав
|
|СГРУППИРОВАТЬ ПО
| Состав.ФизическоеЛицо,
| Состав.ДокументФизическогоЛица
|
|ИМЕЮЩИЕ
| КОЛИЧЕСТВО(*) > 1";
Результат = Запрос.Выполнить();
Проанализируем полученную выборку. Документы, которые попали в результат запроса, необходимо перепровести. В процессе перепроведения встроенные алгоритмы типовой конфигурации перезапишут набор записей регистра СоставДокументовЗарплатаКадры, автоматически выполнив свертку по физическим лицам и устранив дубли.
Так как этот регистр выполняет чисто техническую функцию и не хранит уникальных расчетных данных, мы можем полностью его очистить перед обновлением, а затем восстановить данные автоматически.
Рассмотрим этот надежный алгоритм по шагам:
Набор = РегистрыСведений.СоставДокументовЗарплатаКадры.СоздатьНаборЗаписей();
Набор.Записать(Истина);
СоставДокументовЗарплатаКадры актуальными и корректными данными на основании всех проведенных документов базы.Использование этого метода полностью исключает риск повторного возникновения ошибки реорганизации данных и позволяет обновить систему в кратчайшие сроки.