![]() |
![]() |
![]() |
|
Самоотчет об ошибке "..terminated because a duplicate key was found for index..." ₽ |
☑ | ||
---|---|---|---|---|
0
Serg_1960
24.09.08
✎
12:45
|
Кратко: в SQL-базе ТиИ (реиндексация) завершается по ошибке. По тексту ошибки ясно "в чем" дело, - но не понятно "где"
Попытка вставки неуникального значения в уникальный индекс: Microsoft OLE DB Provider for SQL Server: CREATE UNIQUE INDEX terminated because a duplicate key was found for index ID 1. Most significant primary key is 'type ad, len 16'. HRESULT=80040E2F, SQLSrvr: Error state=1, Severity=10, native=1505, line=1 Понятно что SQL "отвергает" попытку вставки неуникального значения в уникальный индекс. Не понятно только "где" искать проблему. В каком индексе, и главное, - в какой таблице... |
|||
1
Serg_1960
24.09.08
✎
12:58
|
Первое что пришло в голову: выгрузить базу, загрузить в файловую версию и там проверить. Так и сделал... ТиИ (по полной программе) прошло без ошибок. Довольный, выгрузил базу из файловой версии и "попытался" загрузить в SQL-версию... и "пролетел, как фанера над Парижем". Загрузка выдала ошибку:
Ошибка загрузки информационной базы. В информационную базу загружены не все данные по причине: Попытка вставки неуникального значения в уникальный индекс:... далее см. текст выше... Итак, что имеем: Есть РИБ-база на SQL (с ошибками) и файловая база (якобы без ошибок). Все данные вроде-бы "на месте" (проверил "визуально" с помощью формирования на пробу отчетов и повторения различных расчетов) Начал поиски, исходя из утверждения "наверное юзверы напортачили с данными". Например: из узла "пришли" данные с задублированными кодами справочника или номера документов. Решил искать ошибку не там где она есть (в рабочей) а там "где светло" - в файловой копии. Ведь "проблема" сидит там и "передается" в SQL-базу... |
|||
2
Serg_1960
24.09.08
✎
12:59
|
Сообщить("Справочники: контроль на уникальность кода записи");
Для Каждого Объект ИЗ Метаданные.Справочники Цикл Если Объект.КонтрольУникальности > 0 Тогда Имя = Объект.Имя; Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | "+Имя+".Код КАК Код, | КОЛИЧЕСТВО("+Имя+".Ссылка) КАК Количество |ИЗ | Справочник."+Имя+" КАК "+Имя+" | |СГРУППИРОВАТЬ ПО | "+Имя+".Код | |УПОРЯДОЧИТЬ ПО | Количество УБЫВ"; Результат = Запрос.Выполнить(); Если Не Результат.Пустой() Тогда Выборка = Результат.Выбрать(); Пока Выборка.Следующий() И Выборка.Количество > 1 Цикл Сообщить("Справочник(код) "+Объект.Синоним + "(" + Выборка.Код + ")"); КонецЦикла; КонецЕсли; КонецЕсли; КонецЦикла; |
|||
3
Immortal
24.09.08
✎
13:02
|
При ТИИ пишутся имена таблиц, разве не так?
|
|||
4
mikecool
24.09.08
✎
13:04
|
(3) пишется..
у меня такая хрень была с итогами при загрузке базы в скуль, решением служило - рассчитать итоги на начало времен, загрузить, рассчитать итоги на тек период. причем - база выгрузилась с постгри и загружалась в мс скуль |
|||
5
Serg_1960
24.09.08
✎
13:06
|
(3) Так-то оно так, только попробуй успей прочитать. Идет ТиИ - бегут строки. Потом следует большая пауза (уже без сообщений в статусной строке)... и "вылетает" ошибка не понятно уже "к чему" она
|
|||
6
Serg_1960
24.09.08
✎
13:09
|
С Вашего разрешения, я продолжу...
Проверил коды справочников, а потом только "вспомнил" - они здесь "не причем" наличие одинаковых кодов справочников SQL-базе "не помеха"... Решил "проверяться" дальше... Сообщить("Документы: контроль на уникальность номера"); ПериодГод = Метаданные.СвойстваОбъектов.ПериодичностьНомераДокумента.Год; ПериодКвартал = Метаданные.СвойстваОбъектов.ПериодичностьНомераДокумента.Квартал; ПериодМесяц = Метаданные.СвойстваОбъектов.ПериодичностьНомераДокумента.Месяц; ПериодДень = Метаданные.СвойстваОбъектов.ПериодичностьНомераДокумента.День; БезПериода = Метаданные.СвойстваОбъектов.ПериодичностьНомераДокумента.Непериодический; Для Каждого Объект ИЗ Метаданные.Документы Цикл Если Объект.КонтрольУникальности > 0 Тогда Имя = Объект.Имя; Период = Объект.ПериодичностьНомера; Если Период = ПериодГод Тогда Диапазон = "ГОД"; ИначеЕсли Период = ПериодКвартал Тогда Диапазон = "КВАРТАЛ"; ИначеЕсли Период = ПериодМесяц Тогда Диапазон = "МЕСЯЦ"; ИначеЕсли Период = ПериодДень Тогда Диапазон = "ДЕНЬ"; Иначе Диапазон = ""; КонецЕсли; Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | "+Имя+".Номер КАК Номер, | КОЛИЧЕСТВО("+Имя+".Ссылка) КАК Количество |ИЗ | Документ."+Имя+" КАК "+Имя+" | |СГРУППИРОВАТЬ ПО | "+Имя+".Номер"+?(ЗначениеЗаполнено(Диапазон),", НАЧАЛОПЕРИОДА("+Имя+".Дата,"+Диапазон+")", "")+" | |УПОРЯДОЧИТЬ ПО | Количество УБЫВ"; Результат = Запрос.Выполнить(); Если Не Результат.Пустой() Тогда Выборка = Результат.Выбрать(); Пока Выборка.Следующий() И Выборка.Количество > 1 Цикл Сообщить("Документ(номер) "+Объект.Синоним + "(" + Выборка.Номер + ")"); КонецЦикла; КонецЕсли; КонецЕсли; Запрос = Новый Запрос; Запрос.УстановитьПараметр("ДатаС", НачалоГода(Дата("19800101"))); Запрос.УстановитьПараметр("ДатаПо", КонецГода(ТекущаяДата())); Запрос.УстановитьПараметр("БезДаты", Дата("00010101")); Запрос.Текст = " |ВЫБРАТЬ | "+Имя+".Ссылка КАК Документ |ИЗ | Документ."+Имя+" КАК "+Имя+" | |ГДЕ | (НЕ("+Имя+".Дата МЕЖДУ &ДатаС И &ДатаПо) Или "+Имя+".Дата = &БезДаты)"; Результат = Запрос.Выполнить(); Если Не Результат.Пустой() Тогда Выборка = Результат.Выбрать(); Пока Выборка.Следующий() И Выборка.Количество > 1 Цикл Сообщить("Документ(дата) "+Объект.Синоним + " : " + Выборка.Документ); КонецЦикла; КонецЕсли; КонецЦикла; |
|||
7
mikecool
24.09.08
✎
13:09
|
(5) можно поломать голову и написать процедурку по поиску неуникальных значений индексов.. типа пробегать по таблицам, из сис брать имена индексов, и дальше select ... group by ... having count(1)>1
|
|||
8
mikecool
24.09.08
✎
13:10
|
(6) не парься насчет кодов, поскольку ругаться может на кокой-нить составной индекс
|
|||
9
Serg_1960
24.09.08
✎
13:15
|
Все правильно. И я остановился и задумался. "Трудно искать черную кошку в темной комнате - особенно когда ее там нет". Надо было проверять SQL-базу, а не файловую версию (платформа эти ошибки не фиксирует и "в упор не видит")...
А c SQL у меня "проблема": последний раз я с ним работал лет двадцать назад :( Пришлось начинать с азов... |
|||
10
Serg_1960
24.09.08
✎
13:22
|
Большое спасибо авторам Lock1C.epf, StrBaseSQL.epf и (разумеется) сообществу волшебного форума. В течение недели "заново освоил" SQL :о)
Начал с "классического" вопроса новичков... Connection = Новый COMОбъект("ADODB.Connection"); String = "driver={SQL Server};server=SqlSrvr;uid=sa;pwd=PasWord;Database=Base"; String = "Provider=SQLOLEDB.1;Password=PasWord;Persist Security Info=True;User ID=sa;Initial Catalog=Base;Data Source=SQLSRVR"; Connection.ConnectionTimeOut=20; Connection.CommandTimeOut=600; Connection.CursorLocation=3; Сообщить("Установить соединение с базой данных."); Попытка Connection.Open(String); Исключение Сообщить("Ошибка во время установки соединения с базой данных!"); Сообщить(ОписаниеОшибки()); Возврат; КонецПопытки; На всякий случай ДВА варианты строки соединения сейчас указал |
|||
11
mikecool
24.09.08
✎
13:26
|
(10) зачем это все писать в восьмерке?
для дб2 не знаю, а вот для мс скуля есть Qwery Analizer, для постгри и мс есть среда(забыл как производитель называется) наподобие PL\SQL |
|||
12
Immortal
24.09.08
✎
13:32
|
(11) дежавю
|
|||
13
Serg_1960
24.09.08
✎
13:35
|
(11) Ситуация "обострилась" тем, что админ ушел в отпуск "закрыв" SQL-сервер на пароль, и свой телефон "забросил" на #цензура#.
Эх! "Знал бы прикуп - жил бы в Сочи"... Продолжим ? ... в принципе возможны были разные варианты проверки. Но мне они "не помогли":( Сообщить("Проверить структуру SQL-базы командой DBCC CHECKDB..."); Попытка Command = Новый COMОбъект("ADODB.Command"); Command.ActiveConnection=Connection; Command.CommandText="DBCC CHECKDB"; RecordSet = Новый COMОбъект("ADODB.RecordSet"); RecordSet=Command.Execute(); Исключение Сообщить("Ошибка во время проверки базы данных!"); Сообщить(ОписаниеОшибки()); КонецПопытки; Сообщить("Переиндексировать SQL-базу"); Попытка Command = Новый COMОбъект("ADODB.Command"); Command.ActiveConnection=Connection; Command.CommandText="SET NOCOUNT ON |DECLARE @TableName char(32) |DECLARE SysCur CURSOR FOR SELECT name FROM sysobjects WHERE type='U' |OPEN SysCur |FETCH NEXT FROM SysCur INTO @TableName |WHILE @@FETCH_STATUS=0 BEGIN | DBCC DBREINDEX(@TableName) | FETCH NEXT FROM SysCur INTO @TableName |END |CLOSE SysCur |DEALLOCATE SysCur"; RecordSet = Новый COMОбъект("ADODB.RecordSet"); RecordSet=Command.Execute(); Исключение Сообщить("Ошибка во время индексирования базы данных!"); Сообщить(ОписаниеОшибки()); КонецПопытки; |
|||
14
mikecool
24.09.08
✎
13:39
|
(13) раз коннект освоил :) в (7) я описал принцип, по которому сам бы действовал
через systables или syscolumns берем имена таблиц там же в сисах есть и список индексов, надо посмотреть по каждой таблице список индексов, по составу индекса выбрать поля с группировкой и счетчиком, там где больше 1 - дубликат... поточнее написать не могу, поскольку нет доступного скуля... |
|||
15
Serg_1960
24.09.08
✎
13:50
|
(14) Правильные вещи говоришь. Только мне (после баааальшого перерыва) сложно все это было, не только сделать, - но и "понять" что мне советовали...
По мере "усвоения" я написал вот такую "болванку", в которой ставил точки останова и "изучал" что это "такое" я из SQL-я "вытащил" :о) Catalog = Новый COMОбъект("ADOX.Catalog"); Catalog.ActiveConnection=Connection; ВсегоТаблиц = Catalog.Tables.Count-1; Для НомерТаблицы = 0 По ВсегоТаблиц Цикл Таблица = Catalog.Tables.Item(НомерТаблицы); Сообщить("Таблица: " + Таблица.Name + " тип: " + Таблица.Type); Если Таблица.Indexes.Count > 0 Тогда ВсегоИндексов = Таблица.Indexes.Count-1; Для НомерИндекса = 0 По ВсегоИндексов Цикл Индекс = Таблица.Indexes.Item(НомерИндекса); Сообщить(" Индекс: " + Индекс.Name); КонецЦикла; КонецЕсли; Если Таблица.Type = "TABLE" Тогда Попытка Command = Новый COMОбъект("ADODB.Command"); Command.ActiveConnection=Connection; Text = "DBCC DBREINDEX("+СокрЛП(Таблица.Name)+")"; Command.CommandText=Text; RecordSet = Новый COMОбъект("ADODB.RecordSet"); RecordSet=Command.Execute(); Исключение Сообщить("Ошибка во время " + Text); Сообщить(ОписаниеОшибки()); КонецПопытки; КонецЕсли; КонецЦикла; |
|||
16
Serg_1960
24.09.08
✎
13:58
|
Алгорит НеПинатьНогамиСильно. Другие "начинают" писать с фразы "Hello Word" *:о)
Кстати: можно Com-ы сократить и писать Вывод = Connection.Execute("текст команды")... Дальше свои "иследования" приводить не буду. И так ясно что можно выполнять любые алгоритмы на T-SQL... Тем более что ошибка после переиндексации "определилась" |
|||
17
Serg_1960
24.09.08
✎
14:02
|
Ошибка, указанная в (0) была спровоцирована "задвоением" записей в журналах документов. Когда знаешь где искать, - легко найдешь:
Сообщить("Журналы: контроль на уникальность ссылки"); Для Каждого Объект ИЗ Метаданные.ЖурналыДокументов Цикл Имя = Объект.Имя; Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | "+Имя+".Ссылка КАК Ссылка, | КОЛИЧЕСТВО("+Имя+".Ссылка) КАК Количество |ИЗ | ЖурналДокументов."+Имя+" КАК "+Имя+" | |СГРУППИРОВАТЬ ПО | "+Имя+".Ссылка | |УПОРЯДОЧИТЬ ПО | Количество УБЫВ"; Результат = Запрос.Выполнить(); Если Не Результат.Пустой() Тогда Выборка = Результат.Выбрать(); Пока Выборка.Следующий() И Выборка.Количество > 1 Цикл Сообщить("Журнал(ссылки) "+Объект.Синоним + " : " + Выборка.Ссылка); ЗапросСсылки = Новый Запрос; ЗапросСсылки.УстановитьПараметр("Дубль", Выборка.Ссылка); ЗапросСсылки.Текст = "ВЫБРАТЬ | "+Имя+".Дата КАК Дата, | "+Имя+".Номер КАК Номер, | "+Имя+".Ответственный КАК Ответственный |ИЗ | ЖурналДокументов."+Имя+" КАК "+Имя+" | |ГДЕ | "+Имя+".Ссылка = &Дубль | |УПОРЯДОЧИТЬ ПО | Дата, Номер"; ВыборкаСсылки = ЗапросСсылки.Выполнить().Выбрать(); Пока ВыборкаСсылки.Следующий() Цикл Сообщить(" Записи " + ВыборкаСсылки.Дата + " : " + ВыборкаСсылки.Номер + " : " + ВыборкаСсылки.Ответственный); КонецЦикла; КонецЦикла; КонецЕсли; КонецЦикла; |
|||
18
Serg_1960
24.09.08
✎
14:26
|
Осталось сообщить только "разбор полетов":
Ошибка "появилась" после миграции дочернего узла из файлового варианта в SQL под Линукс - ни для меня, ни для моего админа "целина неосвоеная"... Наверное где-то "напартачили" при переходе... Но выбора у нас особо не было. Филиал уже давно "задыхался" - а босам денег было жалко. Вот "в горячах" и перешли "на халяву"... Да совсем забыл :о) В журналах я не стал "копаться" (ни времени, ни желания не было). Я их очистил и с "помощью" ТиИ заново заполнил... В вышеуказанном алгоритме вставил: Если Лев(Таблица.NAME,16) = "_DocumentJournal" Тогда Command.CommandText="TRUNCATE TABLE "+СокрЛП(Таблица.Name)+ " | "+UPDATE STATISTICS "+СокрЛП(Таблица.Name); КонецЕсли; Вот так... теперь можете меня ругать или хвалить... |
|||
19
Serg_1960
24.09.08
✎
19:40
|
Добавлю ссылку http://www.holden.ru/node/19
|
|||
20
Serg_1960
25.09.08
✎
14:56
|
Добавлю алгорит поиска duplicate key для табличных частей справочников. С небольшими переделками можно использовать для табличных частей документов...
Для Каждого Объект ИЗ Метаданные.Справочники Цикл ИмяОбъекта = Объект.Имя; Для Каждого Таблица Из Объект.ТабличныеЧасти Цикл ИмяТаблицы = Таблица.Имя; Состояние(ИмяОбъекта+"."+ИмяТаблицы); Запрос = Новый Запрос; Запрос.Текст = " |ВЫБРАТЬ | " + ИмяТаблицы + ".Ссылка КАК Ссылка, | " + ИмяТаблицы + ".НомерСтроки КАК НомерСтроки, | КОЛИЧЕСТВО(" + ИмяТаблицы + ".НомерСтроки) КАК Количество |ИЗ | Справочник." + ИмяОбъекта + "." + ИмяТаблицы + " КАК " + ИмяТаблицы + " | |СГРУППИРОВАТЬ ПО | " + ИмяТаблицы + ".Ссылка, | " + ИмяТаблицы + ".НомерСтроки | |УПОРЯДОЧИТЬ ПО | Количество УБЫВ"; Выборка = Запрос.Выполнить().Выбрать(); Пока Выборка.Следующий() И Выборка.Количество > 1 Цикл Сообщить(ИмяОбъекта + "." + ИмяТаблицы + "/" + СокрЛП(Выборка.Ссылка) + "/поз." + Выборка.НомерСтроки + "/"); КонецЦикла; КонецЦикла; КонецЦикла; |
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |