1С:Повторяющиеся ключи (duplicate key) и потерянные проводки

Повторяющиеся ключи (duplicate key) и потерянные проводки Сначала определения. Повторяющиеся ключи это значения из набора столбцов некоторой таблицы, которые встречаются в данной таблице более одного раза. Потерянные проводки это строки таблицы _1SENTRY или _1SOPER. Вы спросите – «Почему данные термины используются в заголовке темы вместе?». Потому, что часто (хотя и не всегда) потерянные проводки проявляются как строки с повторяющимися ключами.

Сначала определения.

Повторяющиеся ключи это значения из набора столбцов некоторой таблицы, которые встречаются в данной таблице более одного раза.

Потерянные проводки это строки таблицы _1SENTRY или _1SOPER.

Вы спросите – «Почему данные термины используются в заголовке темы вместе?». Потому, что часто (хотя и не всегда) потерянные проводки проявляются как строки с повторяющимися ключами.

В одной из моих статьей я уже писал как бороться с повторяющимися ключами. Теперь же рассмотрим ситуации, при которых возникают сообщения об ошибках в результате появления повторяющихся ключей. А таковых бывает несколько. Набираем в известном всем Books Online (BOL) сочетание «duplicate key», сортируем по колонке «Местонахождение» и перемещаемся на строки с разделом «Troubleshooting». Получаем:

Native error Код ошибки SQL Severity Уровень «серьезности» ошибки Текст ошибки
1505 14 CREATE UNIQUE INDEX terminated because a duplicate key was found for index ID %d. Most significant primary key is '%S_KEY'.
Невозможно создать уникальный индекс так как в талибце найдены повторяющиеся ключи
1508 14 CREATE INDEX terminated because a duplicate row was found. Primary key is '%S_KEY'.
Невозможно создать кластерный индекс так как в таблице найдены повторяющиеся ключи
2601 14 Cannot insert duplicate key row in object '%.*ls' with unique index '%.*ls'.
Невозможно вставить строки (обновить строки) в таблице, так как для нее создан уникальный индекс и строка с таким ключом уже есть в таблице

Первые две ошибки случаются когда предпринимается попытка создания индекса (уникального или кластерного). Третья ошибка происходит при попытке вставки записи (либо изменении поля существующей записи) и при этом нарушается уникальность уже существующего индекса.

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

Select field,…, fieldN form table group by field,…, fieldN,

здесь field,…, fieldN – набор полей таблицы, по которому создан индекс, уникальный которого нарушается. Это конечно неудобно, так как приходится пролистывать весь запрос для нахождения повторяющихся ключей. Удобнее будет использовать следующий запрос:

select field,…, fieldN, "Count"=count(*) from Table Group by field,…, fieldN having count(*)>1

После получения списка повторяющихся ключей, остается решить какие из них нужно оставить, а какие удалить.

Теперь вернемся к потерянным проводкам. Часто такие сообщения появляются для таблиц _1SENTRY и _1SOPER. Поэтому метод описанные выше также подходит для исправления данных в таблице проводок и операций. Однако кроме этого существуют специфичные для 1С методы борьбы с потерянными проводками:

  • Поставить признак для документа, создающего бухгалтерские проводки, «Всегда создавать операцию». Данный способ лучше всего применять для конфигураций, которые еще не «в бою», то есть только на этапе создания. При разработке конфигурации для SQL платформы всегда ставьте признак «Всегда» ;) для уменьшения вероятности возникновения потерянных проводок.
  • Отмена проведения + проведение документа (ов). Обычно не помогает документам, у которых не стоит признак создавать операцию всегда. И именно при проведении документа возникает данная ошибка.
  • Выгрузка – загрузка данных. Очень действенный метод, но очень долгий.
  • Тестирование + исправление конфигурации. Иногда помогает.

Что рекомендую. Сначала пробуйте отменить проведение документа и провести его заново. Иногда бывает трудно определить у какого документа потерялись проводки. В этом случае данная операция может занять столько же (если не больше) времени сколько загрузка и выгрузка. Если не поможет – тестирование + исправление конфигурации. Если не поможет – почистить проводки с помощью метода борьбы с повторяющимися ключами, провести документ(ы). Крайняя мера – загрузка – выгрузка. Изменение признака операции на «создавать всегда» приведет к пересчету бухгалтерских итогов, поэтому данная операция сравнима по времени с выгрузкой – загрузкой и тестированием с пересчетом итогов. Данную операцию я не применял, но думаю, что ее можно использовть вместо тестирования – исправления конфигурации. В любом случае если вы исправили положение, то для всех бухгалтерских документов лучше поставить признак создавать операцию всегда.

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

-- есть проводки по непроведенным документам
-- такое безобразие нужно "покоцать"
delete from _1sentry (nolock)
where docid in (select iddoc from _1sjourn (nolock)
where closed=0)


-- есть проводки, но нет соответствующих документов
-- такое безобразие нужно "покоцать"
delete from _1sentry (nolock)
where docid not in (select iddoc from _1sjourn (nolock))


-- есть проводки, но нет соответствующих операций
-- такое безобразие нужно "покоцать"
delete from _1sentry (nolock)
where docid not in (select docid from _1soper (nolock))


-- есть операции, но нет соответствующих документов
-- такое безобразие нужно "покоцать"
delete from _1soper (nolock)
where docid not in (select iddoc from _1sjourn (nolock))


-- проверка правильности заполнения DATE_TIME_DOCID в _1sentry
-- вместо проверки - замена на правильный DATE_TIME_DOCID
update _1sentry set DATE_TIME_DOCID=_1sjourn.DATE_TIME_idDOC
from _1sjourn (nolock)
--select _1sentry.DATE_TIME_DOCID,_1sjourn.DATE_TIME_idDOC
from _1sentry (nolock), _1sjourn (nolock)
where _1sentry.DOCID=_1sjourn.idDOC and
      _1sentry.DATE_TIME_DOCID<>_1sjourn.DATE_TIME_idDOC


-- здесь можно сделать установку поля APPCODE, которое содержит
-- флаги, к какой компоненте принадлежит документ (см. статью на
-- hare.ru в разделе Коллективный разум про структуру базы)
-- поле устанавливается для определенного вида документа IDDOCDEF
-- то есть известно какой документ, по какой компоненте делает
-- движения
-- проверка правильности заполнения APPCODE в _1Sjourn
--Update _1Sjourn set appcode=appcode+32
--where appcode<32 and IDDOCDEF<>1356 and
--      iddoc in (select docid from _1sentry (nolock))
-- 32 – заменить на нужный APPCODE
-- 1356 –заменить на нужный IDDOCDEF


-- проверка базы - можно раскомментировать
--dbcc checkdb
-- переиндексация базы данных - можно раскомментировать
--exec _1sp_dbreindex

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

Вот и все. Пишите мне, если у вас есть свои методы борьбы с описанными ситуациями – пополним наш арсенал вашим оружием!

Удачной борьбы с потерянными проводками и повторяющимся ключам – глюками 1С!

Шемякин Павел
1csql@udmnet.ru
http://1csql.virtualave.net/1csql/

Начать дискуссию